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

时间:2012-01-09 23:27:20

标签: python multithreading memory-management

我写了大约50个类,用于连接和使用机械化和线程的网站。它们都同时工作,但它们并不相互依赖。所以这意味着1个类 - 1个网站 - 1个线程。它不是特别优雅的解决方案,特别是对于管理代码,因为很多代码在每个类中重复(但不足以使它成为一个类来传递参数,因为一些站点可能需要在方法中间对检索到的数据进行额外处理 - 像'登录' - 其他人可能不需要)。正如我所说,它并不优雅 - 但它有效。毋庸置疑,我欢迎所有建议如何更好地编写这个,而不使用每个网站方法的1个类。添加每个类的附加功能或整体代码管理是一项艰巨的任务。

但是,我发现,每个线程占用大约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行,我可以在shell中使用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 个答案:

答案 0 :(得分:4)

答案 1 :(得分:2)

使用“每个请求一个线程”对于许多用例来说都很简单。但是,它需要大量的资源(正如您所经历的那样)。

更好的方法是使用异步方法,但不幸的是它要复杂得多。

这方面的一些暗示:

答案 2 :(得分:1)

解决方案是替换这样的代码:

1)做点什么 2)等待事情发生 3)做别的事。

使用这样的代码:

1)做点什么 2)安排它,以便在发生事情时,完成其他事情 3)完成。

在其他地方,你有几个线程可以做到这一点:

1)等待任何事情发生 2)处理发生的事情 3)转到步骤1.

在第一种情况下,如果你要等待50件事情发生,你就会有50个线程等待50件事情发生。在第二种情况下,你有一个线程在等待那50个事情需要完成的任何一个。

所以,不要使用线程等待一件事发生。相反,安排它,以便当事情发生时,其他一些线程将做下一步需要做的事情。

答案 3 :(得分:0)

我不是Python的专家,但可能有一些线程池可以控制活动线程的总数,并且一旦完成前一个线程,就会向线程发出“请求”。请求不必是完整的线程对象,只需要足够的数据来完成请求。

你也可以构建它,这样你就有了线程池A,有N个线程ping网站,一旦检索到数据,就把数据交给线程池B,用Y线程处理数据。