【问题标题】:Multiprocessing Queue do not release memory多处理队列不释放内存
【发布时间】:2012-05-21 10:30:24
【问题描述】:

当 queue.put() 的速度快于 queue.get() 的速度时,我发现 P1 进程将使用大内存(因为 P1 不断地从大文本文件中放入行)。甚至 P2 随后也完成了从队列中取线。 P1 使用的内存仍未释放。如何解决这个问题?下面是示例和测试代码。

谢谢!

import time
from multiprocessing import Process, Queue

def addline(q):
   f = file('a big text file','r')
   line = True
   while line:
      line = f.readline()
      q.put(line, False)
   f.close()
   print "P1:finished"
   while 1:
      time.sleep(2)

def getline(q):
   f = file('/tmp/bak','w') 
   line = True
   while line:
      line=q.get()
      f.write(line)
      time.sleep(0.01)
   f.close()
   print "p2:finished"



if __name__ == "__main__":
   q = Queue()
   p1 = Process(name="addline", target=addline, args=(q,))
   p2 = Process(name="getline", target=getline, args=(q,))
   p1.start()
   p2.start()

编辑: 我尝试读取一个文本文件(44MB)并观察 /proc/pid/smaps。发现未释放的内存在堆中变成了Private_Dirty。

00fb3000-04643000 rw-p 00000000 00:00 0                                  [heap]
Size:              55872 kB
Rss:               55844 kB
Pss:               55163 kB
Shared_Clean:          0 kB
Shared_Dirty:       1024 kB
Private_Clean:         0 kB
Private_Dirty:     54820 kB
Referenced:        54972 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB

 

【问题讨论】:

  • 你在getline()中用while 1: q.get()做什么?
  • 在这个测试用例中,我只想保留P2。我已经删除了它。谢谢。
  • 您是否考虑过为队列设置限制?如果读取过程跟不上,那么整个内容必须无限制地缓存在队列中。
  • 有什么方法可以清理已读取的缓冲区吗?非常感谢。
  • @jess 你有解决办法吗

标签: python queue multiprocessing


【解决方案1】:

一旦对象不再被引用,Python 的垃圾收集器就会删除它。只要写入速率可以跟上存储硬件的读取速率,就必须可以在不增加内存且内存占用量小的情况下,从两个独立的线程/进程同时读取文件内容并同时写入文件内容。我相信当您使用更适合您的用例的 Python 语言结构时,您的问题就会消失。我会尝试对此发表评论。

要逐行读取文件,您应该使用以下概念:

with open('filepath') as f:
    for line in f:
        do_something_with(line)

然后您不必显式地.close() 文件。这同样适用于写入文件。在此处阅读with 声明:http://effbot.org/zone/python-with-statement.htm

在我看来,对于您提出的用例,multiprocessing.Pipe 而不是multiprocessing.Queue 会更合适,因为它是“类流”应用程序。将原始文件内容表示为队列中的项目似乎很奇怪。此外,如果您使用线程而不是独立的子进程(那么您应该使用os.pipe 进行线程间通信)**,您可以摆脱大量的通信开销。无论如何,你应该在启动它们之后join()线程和子进程。

** 对于您的用例(复制文件),全局解释器锁 (GIL) 不会是性能问题。

【讨论】:

  • 感谢您的回复!!在我的真实案例中,我必须收集很多资源。为了避免 GIL 问题,我使用了 multiprocessing 和 multiprocessing.Queue。关于读取文件,我使用了生成器。 Queue.get 之后,P2 会对其进行分析,所以 P2 比 P1 慢。然后 P1 将使用内存并且不释放它。我不知道如何解决它。
  • 如果您的数据分析速度明显慢于读取文件,并且您不希望有一个大缓冲区(即内存使用量增加),那么除了实施反馈机制之外别无选择:读者需要一些指示何时暂停读取数据。
  • 在正常情况下分析仪足够快,所以阅读器不使用内存。但恐怕也有一些例外。而且我很好奇为什么缓冲区不释放,甚至读者也从缓冲区获取数据。谢谢!
猜你喜欢
  • 1970-01-01
  • 2014-03-21
  • 1970-01-01
  • 2021-01-11
  • 1970-01-01
  • 2013-07-02
  • 2012-07-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多