繁体   English   中英

如何使用multiprocessing.Pool异步没有回调?

[英]How to use multiprocessing.Pool async without callbacks?

所以,我有一个问题,我认为必须是常见的:

我想将脚本与multiprocessing.Pool并行化,将输入交给池,让它并行处理它们,并在父进程中接收输出。

apply_async()看起来最适合我想做的事情。 但我不能只给出一个回调函数,因为最后我想将所有结果打印到一个文件中。 我认为将一个回调打印到单个文件句柄会导致混乱的结果(甚至不能确定我可以在这样的进程之间传递文件句柄)。

那么如何向Pool提交输入,然后接收输出并在主进程中处理它们的最佳方法是什么? 目前我只是在列表中收集AsyncResult对象并定期迭代它,在每个上调用.get()方法。

更新

我将在回应评论时澄清我的问题的一些参数:

  1. @martineau和@Juggernaut:不是“混乱”,我的意思是我真的想保留输入的顺序,以便输出顺序相同。

  2. @RolandSmith和@martineau:我的主要过程就是从文件读取输入,将它们交给池,然后打印结果。 我可以调用.apply() ,但是然后主进程在它继续之前等待函数完成。 我正在使用multiprocessing来获得并行化的好处并同时处理许多输入。

为了回答你的问题,我不认为你可以在没有回调的情况下做你想做的事。

您希望异步计算结果,但是以与输入相同的顺序打印。 这意味着不仅必须等到所有输入在打印之前都被处理,而且还要知道它们在输入中的相对位置,以便在输出它们之前将它们排序回该顺序。

因此,这里是如何一个做到这一点。 正如我之前所说,稍微棘手的部分是结果必须包含指示输入的相应位置的东西,因此结果可以在打印之前以类似的顺序排序。 由于该要求,脚本必须等到所有输入都已处理完毕。

请注意,尽管如此,您还是可以获得并行处理的好处,因为并发处理会创建单个结果本身。

import multiprocessing as mp
from random import randint
from time import sleep

def my_func(*args):
    print('my_func:', args)
    index, x = args
    sleep(randint(1, 3))  # Take a varying amount of time to finish.
    return index, x*x  # Return result index and value.

if __name__ == '__main__':

    result_list = []

    def errorhandler(exc):
        print('Exception:', exc)

    def log_result(result):
        # This is called whenever my_func() returns a result.
        # result_list is modified only by the main process, not the pool workers.
        result_list.append(result)

    pool = mp.Pool()
    for i in range(10):
        pool.apply_async(my_func, args=(i, i*2), callback=log_result,
                         error_callback=errorhandler)
    pool.close()
    pool.join()  # Wait for all subprocesses to finish.

    print('result_list:', result_list)
    sorted_results = [x[1] for x in sorted(result_list)]
    print('sorted results:', sorted_results)

输出:

my_func: (5, 10)
my_func: (1, 2)
my_func: (4, 8)
my_func: (7, 14)
my_func: (3, 6)
my_func: (9, 18)
my_func: (0, 0)
my_func: (6, 12)
my_func: (2, 4)
my_func: (8, 16)
result_list: [(2, 16), (3, 36), (5, 100), (1, 4), (4, 64), (7, 196), (9, 324), (0, 0), (6, 144), (8, 256)]
sorted results: [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]

正如您在评论中所要求的,这里的代码显示了如何使用Pool.map()而不是Pool.async() - 这似乎更适合此问题,因为需要在进一步输出之前等待所有结果处理可以完成(例如,它需要与输入的顺序相同)。

正如您所看到的,它需要的代码要少得多 ,并且在输出结果之前不需要对结果进行排序(因此也可能更快)。

import multiprocessing as mp
from random import randint
from time import sleep

def my_func(x):
    print('my_func:', x)
    sleep(randint(1, 3))  # Take a varying amount of time to finish.
    return x*x

if __name__ == '__main__':

    input_data = range(10)
    with mp.Pool(10) as pool:
        result_list = pool.map(my_func, input_data)  # Blocks until finished.

    print('result_list:', result_list)  # Will be in same order as input_data.

输出:

my_func: 3
my_func: 2
my_func: 1
my_func: 0
my_func: 8
my_func: 5
my_func: 7
my_func: 6
my_func: 4
my_func: 9
result_list: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

我认为将它打印到单个文件句柄的回调将导致结果混乱

解决方案是使用结果填充回调中的Queue ,然后再获取它们。 队列是线程安全的,因此您不必担心您所谈论的混乱结果。

from queue import Queue
results = Queue()

def callback(result):
    results.put(result)

后来

item = results.get()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM