如何减少多线程Python代码的内存使用?

7 投票
4 回答
16935 浏览
提问于 2025-04-17 09:53

我写了大约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

解决方法是把这样的代码:

1) 做一些事情。
2) 等待某件事情发生。
3) 再做其他事情。

换成这样的代码:

1) 做一些事情。
2) 安排好,当某件事情发生时,其他事情就会被处理。
3) 完成。

在其他地方,你有几个线程在做这个:

1) 等待任何事情发生。
2) 处理发生的事情。
3) 回到第一步。

在第一种情况下,如果你在等50件事情发生,就会有50个线程在那儿等着这50件事情。而在第二种情况下,只有一个线程在等,它会处理这50件事情中需要处理的任何一件。

所以,不要用一个线程去等一件事情发生。相反,应该安排好,当那件事情发生时,其他线程会去处理接下来需要做的事情。

2

每个请求用一个线程来处理,这种方法在很多情况下是可以的,而且也比较简单。不过,这样做会消耗很多资源(就像你体验到的那样)。

一个更好的方法是使用异步处理,但可惜的是,这种方法要复杂得多。

这里有一些相关的建议:

6

撰写回答