什么';使用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',
                '!@#$%^&*()',
            ],
        )