到目前为止,每当我需要使用multiprocessing
时,我都是通过手动创建“进程池”并与所有子进程共享工作队列来完成的。
例如:
from multiprocessing import Process, Queue
class MyClass:
def __init__(self, num_processes):
self._log = logging.getLogger()
self.process_list = []
self.work_queue = Queue()
for i in range(num_processes):
p_name = 'CPU_%02d' % (i+1)
self._log.info('Initializing process %s', p_name)
p = Process(target = do_stuff,
args = (self.work_queue, 'arg1'),
name = p_name)
这样我可以在队列中添加东西,这些东西将由子进程使用。然后,我可以通过检查Queue.qsize()
:
while True:
qsize = self.work_queue.qsize()
if qsize == 0:
self._log.info('Processing finished')
break
else:
self._log.info('%d simulations still need to be calculated', qsize)
现在我认为multiprocessing.Pool
可以简化这段代码。
我无法找到的是如何监控仍有待完成的“工作量”。
采用以下示例:
from multiprocessing import Pool
class MyClass:
def __init__(self, num_processes):
self.process_pool = Pool(num_processes)
# ...
result_list = []
for i in range(1000):
result = self.process_pool.apply_async(do_stuff, ('arg1',))
result_list.append(result)
# ---> here: how do I monitor the Pool's processing progress?
# ...?
有什么想法吗?
答案 0 :(得分:14)
使用Manager
队列。这是在工作进程之间共享的队列。如果您使用普通队列,它将被每个工作人员腌制和取消,并因此被复制,这样每个工作人员都不能更新队列。
map_async
执行此操作,因为这可以让您查看整个结果何时准备好,从而允许您中断监视循环。
示例:
import time
from multiprocessing import Pool, Manager
def play_function(args):
"""Mock function, that takes a single argument consisting
of (input, queue). Alternately, you could use another function
as a wrapper.
"""
i, q = args
time.sleep(0.1) # mock work
q.put(i)
return i
p = Pool()
m = Manager()
q = m.Queue()
inputs = range(20)
args = [(i, q) for i in inputs]
result = p.map_async(play_function, args)
# monitor loop
while True:
if result.ready():
break
else:
size = q.qsize()
print(size)
time.sleep(0.1)
outputs = result.get()
答案 1 :(得分:2)
我遇到了同样的问题,并为MapResult对象提出了一个简单的解决方案(虽然使用内部MapResult数据)
pool = Pool(POOL_SIZE)
result = pool.map_async(get_stuff, todo)
while not result.ready():
remaining = result._number_left * result._chunksize
sys.stderr.write('\r\033[2KRemaining: %d' % remaining)
sys.stderr.flush()
sleep(.1)
print >> sys.stderr, '\r\033[2KRemaining: 0'
请注意,剩余的值并不总是准确的,因为块大小通常会被舍入,具体取决于要处理的项目数。
您可以使用pool.map_async(get_stuff, todo, chunksize=1)
答案 2 :(得分:1)
我想出了async_call的解决方案。
琐碎的玩具脚本示例但我应该广泛应用。
基本上在无限循环中轮询结果对象在列表生成器中的就绪值,并求和以计算剩余的已分派池任务的数量。
一旦没有剩下休息和加入()&关闭()。
根据需要在循环中添加sleep。
与上述解决方案相同但没有队列的原则。如果您还跟踪最初发送池的任务数量,您可以计算完成百分比等等......
import multiprocessing
import os
import time
from random import randrange
def worker():
print os.getpid()
#simulate work
time.sleep(randrange(5))
if __name__ == '__main__':
pool = multiprocessing.Pool(processes=8)
result_objs = []
print "Begin dispatching work"
task_count = 10
for x in range(task_count):
result_objs.append(pool.apply_async(func=worker))
print "Done dispatching work"
while True:
incomplete_count = sum(1 for x in result_objs if not x.ready())
if incomplete_count == 0:
print "All done"
break
print str(incomplete_count) + " Tasks Remaining"
print str(float(task_count - incomplete_count) / task_count * 100) + "% Complete"
time.sleep(.25)
pool.close()
pool.join()
答案 3 :(得分:0)
从文档中,我认为您想要做的是在列表或其他序列中收集result
,然后迭代结果列表检查ready
以构建输出列表。然后,您可以通过将未处于就绪状态的剩余结果对象的数量与分派的作业总数进行比较来计算处理状态。见http://docs.python.org/2/library/multiprocessing.html#multiprocessing.pool.AsyncResult