什么';使用multiprocessing.Pool进行映射,同时附加到迭代器的python方法是什么?
使用带有进程池的队列似乎是一种常见的模式,即什么';使用multiprocessing.Pool进行映射,同时附加到迭代器的python方法是什么?,python,multiprocessing,Python,Multiprocessing,使用带有进程池的队列似乎是一种常见的模式,即 Pool(2).map(f, xs) 但是,f的主体可以附加到映射到的项,例如 from multiprocessing import Pool xs = [0] def f(n): global xs if n < 10: xs.append(n + 1) return n Pool(2).map(f, xs) 来自多处理导入池的 xs=[0] def f(n): 全局xs 如果n32767个
Pool(2).map(f, xs)
但是,f的主体可以附加到映射到的项,例如
from multiprocessing import Pool
xs = [0]
def f(n):
global xs
if n < 10:
xs.append(n + 1)
return n
Pool(2).map(f, xs)
来自多处理导入池的
xs=[0]
def f(n):
全局xs
如果n<10:
追加(n+1)
返回n
池(2).map(f,xs)
期望返回[0,1,2,3,4,5,6,7,8,9]
我意识到用mt提供的原语构建这个“”是可能的,但它似乎是一个足够常见的模式,因此必须有一个通用的解决方案。你知道吗?根据@martineau的建议,你的代码可以更新为:
import multiprocessing as mp
def f(n, xs, xn):
if n < 10:
xn.append(n)
xs.append(n + 1)
xn.append(n)
xs.append(n + 2)
if __name__ == '__main__':
with mp.Manager() as manager:
xs = manager.list()
xn = manager.list()
with mp.Pool(processes=2) as pool:
pool.starmap(f, [(n, xs, xn) for n in range(20)])
print(xn)
print(xs)
因此,您无法保证n个值的生成顺序得到保留
编辑:
您可以创建一个类,该类使用以下基本体执行此操作:
from multiprocessing import JoinableQueue, Process
class PoolQueue(object):
def __init__(self, n):
self.num_procs = n
def map(self, f, args):
payloads = JoinableQueue()
procs = []
def add_task(arg):
payloads.put(arg)
def process_task():
while True:
pl = payloads.get()
f(pl, add_task)
payloads.task_done()
for arg in args:
add_task(arg)
procs = [Process(target=process_task) for _ in range(self.num_procs)]
for p in procs:
p.start()
payloads.join()
for p in procs:
p.kill()
要测试它,请运行-
from time import sleep
from random import random
def pause():
sleep(random() / 100)
def process(payload, add_task):
print(payload)
pause()
if payload:
add_task(payload[:-1])
return payload
if __name__ == '__main__':
for x in range(1):
PoolQueue(2).map(
process,
[
'abcdefghij',
'0123456789',
'!@#$%^&*()',
],
)
这里的一个问题是它会死锁队列增长>32767个任务。
gevent.queue.JoinableQueue
可以更好地处理这个问题,但这超出了这个问题的范围。谢谢-它不能被迭代,我意识到我可以用它来手动完成一些事情[1],但对于这样一个简单而常见的任务来说,它似乎太复杂了。1:每个进程都在自己的内存空间中运行,因此不能共享对全局变量(如xs
)的访问。请参阅文档中的内容。感谢您的努力,但这并不是我想要的。如果是这样的话,那么将<10
更改为<1000
将导致大约100倍的输出。@AndreyFedorov是否修改了范围函数内的值?我修改了我的问题以简化示例,并为xs=[0]
的输入添加了一个输出——这更有意义吗?我更新了我的答案。希望它更符合你的期望。请注意,您仍然需要更改n
上的条件和在范围中给出的值。max(xs)
上的条件是避免由于无序执行而合并任何更大的数字。抱歉,否——如果您没有传入range(20)
,而是传入[0]
,则我希望得到此输出,因为函数f
将调用xs.append(1)
,map函数将处理并调用xs.append(2)
,等等。我将添加一个最好的答案,我有w.r.t.代码,可以做类似的事情,但我仍然不知道为什么这不是使用内置的可以做的事情。
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
from multiprocessing import JoinableQueue, Process
class PoolQueue(object):
def __init__(self, n):
self.num_procs = n
def map(self, f, args):
payloads = JoinableQueue()
procs = []
def add_task(arg):
payloads.put(arg)
def process_task():
while True:
pl = payloads.get()
f(pl, add_task)
payloads.task_done()
for arg in args:
add_task(arg)
procs = [Process(target=process_task) for _ in range(self.num_procs)]
for p in procs:
p.start()
payloads.join()
for p in procs:
p.kill()
from time import sleep
from random import random
def pause():
sleep(random() / 100)
def process(payload, add_task):
print(payload)
pause()
if payload:
add_task(payload[:-1])
return payload
if __name__ == '__main__':
for x in range(1):
PoolQueue(2).map(
process,
[
'abcdefghij',
'0123456789',
'!@#$%^&*()',
],
)