如何减少多线程Python代码的内存使用?
我写了大约50个类,用来连接和操作网站,使用了mechanize和线程。这些类都是同时工作的,但彼此之间没有依赖关系。也就是说,每个类对应一个网站和一个线程。这种做法并不是特别优雅,特别是在管理代码方面,因为每个类里的代码有很多重复(但又不够多到可以合并成一个类来传递参数,因为有些网站可能需要在方法中间对获取的数据进行额外处理,比如“登录”,而其他网站可能就不需要)。正如我所说,这种方法并不优雅——但它确实能工作。不用说,我欢迎所有关于如何更好地编写代码的建议,而不是为每个网站使用一个类。增加额外的功能或管理每个类的整体代码是一项艰巨的任务。
不过,我发现每个线程大约占用8MB的内存,所以50个线程同时运行的话,内存使用量大约是400MB。如果在我的系统上运行,我倒是没什么问题,但由于它是在只有1GB内存的VPS上运行,这就开始成问题了。你能告诉我如何减少内存使用吗?或者有没有其他方法可以同时处理多个网站?
我使用了这个快速测试的Python程序,来检查是我应用程序中存储在变量里的数据占用了内存,还是其他原因。正如你在下面的代码中看到的,它只在处理sleep()函数,但每个线程仍然使用8MB的内存。
from thread import start_new_thread
from time import sleep
def sleeper():
try:
while 1:
sleep(10000)
except:
if running: raise
def test():
global running
n = 0
running = True
try:
while 1:
start_new_thread(sleeper, ())
n += 1
if not (n % 50):
print n
except Exception, e:
running = False
print 'Exception raised:', e
print 'Biggest number of threads:', n
if __name__ == '__main__':
test()
当我运行这个程序时,输出是:
50
100
150
Exception raised: can't start new thread
Biggest number of threads: 188
通过去掉running = False
这一行,我可以使用free -m
命令在终端中测量可用内存:
total used free shared buffers cached
Mem: 1536 1533 2 0 0 0
-/+ buffers/cache: 1533 2
Swap: 0 0 0
我知道每个线程大约占用8MB内存的实际计算很简单,就是将测试应用程序运行前后的内存使用差值,除以它能启动的最大线程数。
这可能只是分配的内存,因为从top
命令来看,Python进程只使用了大约0.6%的内存。
4 个回答
解决方法是把这样的代码:
1) 做一些事情。
2) 等待某件事情发生。
3) 再做其他事情。
换成这样的代码:
1) 做一些事情。
2) 安排好,当某件事情发生时,其他事情就会被处理。
3) 完成。
在其他地方,你有几个线程在做这个:
1) 等待任何事情发生。
2) 处理发生的事情。
3) 回到第一步。
在第一种情况下,如果你在等50件事情发生,就会有50个线程在那儿等着这50件事情。而在第二种情况下,只有一个线程在等,它会处理这50件事情中需要处理的任何一件。
所以,不要用一个线程去等一件事情发生。相反,应该安排好,当那件事情发生时,其他线程会去处理接下来需要做的事情。
- 使用更少的线程:可以参考这个ThreadPoolExecutor的例子。如果你在用Python 2.x,可以安装
futures
这个库。 - 尝试异步的方法:
- 可以看看这个gevent的例子
- 还有这个twisted的例子