如何通过 multiprocessing.Pool 判断 apply_async 函数是否已启动或者是否仍在队列中

Ale*_*lex 5 python parallel-processing python-multiprocessing

我正在使用 python 的 multiprocessing.Pool 和 apply_async 来调用一堆函数。

如何判断函数是否已开始由池中的成员处理或者是否位于队列中?

例如:

import multiprocessing
import time

def func(t):
    #take some time processing
    print 'func({}) started'.format(t)
    time.sleep(t)

pool = multiprocessing.Pool()

results = [pool.apply_async(func, [t]) for t in [100]*50] #adds 50 func calls to the queue

Run Code Online (Sandbox Code Playgroud)

对于每个AsyncResultin,results您可以调用ready()get(0)来查看 func 是否完成运行。但是如何知道 func 是否 已开始但尚未完成呢?

即对于给定的 AsyncResult 对象(即给定的结果元素),有没有办法查看该函数是否已被调用或者它是否位于池的队列中?

Bra*_*Dre 3

首先,从结果列表中删除已完成的作业

    results = [r for r in results if not r.ready()]
Run Code Online (Sandbox Code Playgroud)

待处理进程数是结果列表的长度:

    pending = len(results)
Run Code Online (Sandbox Code Playgroud)

待处理但未启动的数量为待处理总数 - pool_size

    not_started = pending - pool_size
Run Code Online (Sandbox Code Playgroud)

如果像您一样使用默认参数创建 Pool,则 pool_size 将是 multiprocessing.cpu_count()

更新:在最初误解了这个问题之后,这里有一种方法可以完成OP所询问的事情。

我怀疑这个功能可以添加到 Pool 类中而不会有太多麻烦,因为 AsyncResult 是由带有队列的 Pool 实现的。该队列还可以在内部使用来指示是否已启动。

但这里有一种使用 Pool 和 Pipe 来实现的方法。注意:这在 Python 2.x 中不起作用——不知道为什么。在 Python 3.8 中测试。

import multiprocessing
import time
import os

def worker_function(pipe):
    pipe.send('started')
    print('[{}] started pipe={}'.format(os.getpid(), pipe))
    time.sleep(3)
    pipe.close()

def test():
    pool = multiprocessing.Pool(processes=2)
    print('[{}] pool={}'.format(os.getpid(), pool))

    workers = []

    for x in range(1, 4):
        parent, child = multiprocessing.Pipe()
        pool.apply_async(worker_function, (child,))
        worker = {'name': 'worker{}'.format(x), 'pipe': parent, 'started': False}
        workers.append(worker)

    pool.close()

    while True:
        for worker in workers:
            if worker.get('started'):
                continue
            pipe = worker.get('pipe')
            if pipe.poll(0.1):
                message = pipe.recv()
                print('[{}] {} says {}'.format(os.getpid(), worker.get('name'), message))
                worker['started'] = True
                pipe.close()
        count_in_queue = len(workers)
        for worker in workers:
            if worker.get('started'):
                count_in_queue -= 1
        print('[{}] count_in_queue = {}'.format(os.getpid(), count_in_queue))
        if not count_in_queue:
            break
        time.sleep(0.5)

    pool.join()

if __name__ == '__main__':
    test()
Run Code Online (Sandbox Code Playgroud)