我有以下设置:
import multiprocessing
def heavy_work(args):
queue, data, idx = args
state = 0
for elem in queue:
# decide how to process current data point, store collected information in 'state'
else:
queue.put(modify(data[idx], state))
def mp_heavy_work(data):
queue = multiprocessing.Manager().Queue(len(data))
pool = multiprocessing.Pool(processes=4)
pool.map(heavy_work, ((queue, data, i) for i in range(len(data))))
问题是,队列不可迭代,因此第5行不起作用。我需要知道如何修改以前的数据点以便决定新的数据点,因此读取write-access共享容器(当前为queue
)是必要的。我想依靠一个原始的'进程安全类型而不是锁,因为主要工作是在循环内部完成的 - 所以每次进程进入时锁定它都会使多处理变得多余。
有办法吗?
答案 0 :(得分:0)
为什么需要它可迭代?您可以使用普通queue.get()
。
try:
while True:
elem = queue.get(False)
# do stuff with elem
except Queue.Empty:
queue.put(modify(data[idx], state))
如果你真的想要一个可迭代的,你可以包装你的队列对象:
for elem in iter(queue.get, 'sentinal'):
# do stuff
else:
# do more stuff
这将在每次迭代时调用queue.get,直到它到达“sentianal”对象,然后它将StopIteration
。这样您就可以手动关闭队列。
如果要在队列为空时执行else
阻止(不手动结束迭代),则必须依赖Queue.Empty异常:
try:
for elem in iter(lambda:queue.get(False), 'sentinal'):
# do stuff
except Queue.Empty:
# do else stuff
您甚至可以将它包装在您自己的自定义包装器中:
def wrap(queue):
try:
for elem in iter(lambda:queue.get(False), 'sentinal'):
yield elem
else:
# this is executed if the 'sentinal' is sent
# may want to special handle this (throw custom exception?)
except Queue.Empty:
pass # just enter iteration
...
for elem in wrap(queue):
# do stuff
else:
# do more stuff