使用Pool.apply_async运行大量任务(具有大参数)时,将分配进程并进入等待状态,并且对等待进程的数量没有限制。这可能最终会占用所有内存,如下例所示:
import multiprocessing
import numpy as np
def f(a,b):
return np.linalg.solve(a,b)
def test():
p = multiprocessing.Pool()
for _ in range(1000):
p.apply_async(f, (np.random.rand(1000,1000),np.random.rand(1000)))
p.close()
p.join()
if __name__ == '__main__':
test()
我正在寻找一种限制等待队列的方法,使得只有有限数量的等待进程,并且在等待队列已满时阻塞了Pool.apply_async。
答案 0 :(得分:6)
multiprocessing.Pool
的{{1}}成员类型为_taskqueue
,其中包含可选的multiprocessing.Queue
参数;不幸的是,它没有maxsize
参数集构建它。
我建议将maxsize
子类化为multiprocessing.Pool
的复制粘贴,将multiprocessing.Pool.__init__
传递给maxsize
构造函数。
对对象(池或队列)进行猴子修补也会有效,但你必须使用monkeypatch _taskqueue
和pool._taskqueue._maxsize
这样才会很脆弱:
pool._taskqueue._sem
答案 1 :(得分:1)
等待pool._taskqueue
超过所需的大小:
import multiprocessing
import numpy as np
import time
def f(a,b):
return np.linalg.solve(a,b)
def test(max_apply_size=100):
p = multiprocessing.Pool()
for _ in range(1000):
p.apply_async(f, (np.random.rand(1000,1000),np.random.rand(1000)))
while pool._taskqueue.qsize() > max_apply_size:
time.sleep(1)
p.close()
p.join()
if __name__ == '__main__':
test()
答案 2 :(得分:1)
这是最佳答案的猴子修补替代方案:
import queue
from multiprocessing.pool import ThreadPool as Pool
class PatchedQueue():
"""
Wrap stdlib queue and return a Queue(maxsize=...)
when queue.SimpleQueue is accessed
"""
def __init__(self, simple_queue_max_size=5000):
self.simple_max = simple_queue_max_size
def __getattr__(self, attr):
if attr == "SimpleQueue":
return lambda: queue.Queue(maxsize=self.simple_max)
return getattr(queue, attr)
class BoundedPool(Pool):
# Override queue in this scope to use the patcher above
queue = PatchedQueue()
pool = BoundedPool()
pool.apply_async(print, ("something",))
这在 Python 3.8 中按预期工作,其中多处理池使用 queue.SimpleQueue
来设置任务队列。听起来 multiprocessing.Pool
的实现可能自 2.7 以来发生了变化
答案 3 :(得分:0)
您可以使用maxsize参数添加显式队列,在这种情况下使用queue.put()
代替pool.apply_async()
。然后工人流程可以:
for a, b in iter(queue.get, sentinel):
# process it
如果要将内存中创建的输入参数/结果的数量限制为大约活动工作进程的数量,则可以使用pool.imap*()
方法:
#!/usr/bin/env python
import multiprocessing
import numpy as np
def f(a_b):
return np.linalg.solve(*a_b)
def main():
args = ((np.random.rand(1000,1000), np.random.rand(1000))
for _ in range(1000))
p = multiprocessing.Pool()
for result in p.imap_unordered(f, args, chunksize=1):
pass
p.close()
p.join()
if __name__ == '__main__':
main()