如何管理进程池?

时间:2018-09-28 13:56:16

标签: python windows events multiprocessing pool

我正在尝试在Windows 10上建立一个多处理池。

基本上,一些cpus(在我的情况下为12)应从Qin读取并将结果写入Qout。在'end'中写入Qin时,该过程应停止。

由于某种原因该进程挂起。

我开发了一个简单的版本:

from multiprocessing import Pool, Queue, Event
import os,time


def worker( Qin, Qout, event):
    time.sleep(5)
    while True:
        item = Qin.get()
        if item == 'end':
            event.set()
        else:
            Qout.put(item)
        time.sleep(1)

def manager():
    Qin,Qout,event= Queue(), Queue(), Event()
    processes = os.cpu_count()
    pool = Pool(processes=processes)
    for _ in range(processes):
        pool.apply_async(worker,args= (Qin,Qout,event,))
    for i in range(100):
        print(i)
        Qin.put(i)

    Qin.put('end')

    pool.close()
    event.wait()
    pool.terminate()
    return Qout

Qout = manager()

2 个答案:

答案 0 :(得分:0)

您需要了解异步编程如何在python中正常工作。调用apply_async时,将获得Future对象。 python中的Queue实现依赖于系统管道将数据从一个进程传输到另一个进程以及一些信号量,以保护对该管道的读写。

from multiprocessing import Pool, Queue, Event
import os
import time
import multiprocessing

def worker( Qin, Qout, event):
    print('worker')
    time.sleep(1)
    event.set()

def manager():
    processes = multiprocessing.cpu_count()
    m = multiprocessing.Manager()
    Qin = m.Queue()
    Qout = m.Queue()
    event = m.Event()
    pool = Pool(processes=processes)
    result = pool.apply_async(worker, (Qin, Qout, event))
    result.get()
    pool.close()
    event.wait()
    return Qout

if __name__ == '__main__':
    Qout = manager()

答案 1 :(得分:0)

我认为您的代码挂起的原因是,由于所有item = Qin.get()“阻塞”等待,所有工作任务最终都等待着get()行同时出现在输入队列中要放在队列中的东西。避免这种情况的一种方法是改用非阻塞get_nowait()方法。这样做需要代码处理它可能引发的任何Empty异常,但要避免在该过程中有效地停止该进程中的任何进一步执行。

要使事情正常进行,还需要创建并使用multiprocessing.Manager来创建一个服务器进程,该服务器进程包含Python对象,并允许其他进程通过代理对其进行操作。请参阅文档Sharing state between processes部分的“服务器进程”部分。

此外,在Windows上使用multiprocessing时,通过将主进程的代码放入if __name__ == '__main__':语句中来确保有条件地执行该代码非常重要。这是因为该模块是如何在该平台上实现的-否则,每次启动另一个并发任务(涉及到它们import对其执行操作)时,都会再次执行代码。

下面是需要修改的代码,因此它使用multiprocessing.Manager。请注意,我更改了manager()函数的名称,以避免与用于创建共享库的multiprocessing.Manager混淆。

import multiprocessing
from queue import Empty as QueueEmpty
import os
import time

END_MARKER = 'end'


def worker(id, Qin, Qout, event):
    while True:
        try:
            item = Qin.get_nowait()  # Non-blocking.
        except QueueEmpty:
            if event.is_set():  # Last item seen?
               break
            continue # Keep polling.

        if item == END_MARKER:  # Last item?
            event.set()
            break  # Quit.

        Qout.put('{} via worker {}'.format(item, id))
        time.sleep(.25)


def pool_manager():
    processes = os.cpu_count()
    pool = multiprocessing.Pool(processes=processes)
    manager = multiprocessing.Manager()
    Qin, Qout, event = manager.Queue(), manager.Queue(), manager.Event()

    for i in range(100):
        Qin.put(i)

    Qin.put(END_MARKER)

    for id in range(processes):
        pool.apply_async(worker, (id, Qin, Qout, event))

    pool.close()  # Done adding tasks.
    pool.join()  # Wait for all tasks to complete.

    return Qout


if __name__ == '__main__':
    print('Processing')
    Qout = pool_manager()

    print('Contents of Qout:')
    while not Qout.empty():
        item = Qout.get()
        print(' ', item)

    print('End of script')