繁体   English   中英

如何确保多处理队列为空

[英]How to assure the multiprocessing queue is empty

下面的代码首先启动多个过程。 然后,它运行while True循环,检查queue对象。 最后,它迭代过程以检查是否还活着。 所有过程完成后,它将breaks while循环。 不幸的是,它在queue对象不为空时发生。 在没有将数据存储在queue情况下中断循环可能很容易检查数据丢失。 如何修改代码逻辑,以确保在中断循环之前queue对象为空?

import time, multiprocessing, os
logger = multiprocessing.log_to_stderr()

def foo(*args):
    for i in range(3):
        queue = args[0]
        queue.put(os.getpid())

items = dict()
for i in range(5):
    queue = multiprocessing.Queue()
    proc = multiprocessing.Process(target=foo, args=(queue,))
    items[proc] = queue
    proc.start()
    time.sleep(0.1)

while True:
    time.sleep(1)

    for proc, queue in items.items():
        if not queue.empty():
            print(queue.get()) 

    if not True in [proc.is_alive() for proc in items]:
        if not queue.empty():
            logger.warning('...not empty: %s' % queue.get()) 
        break 

同步问题,再次。 当您检查队列发现它为空时,不能保证将来不会有新项目出现。

您可以在子流程完成其工作时将标记放置在队列中,以通知队列中将没有更多项目。 父进程可能会耗尽队列,直到得到前哨。 这也是multiprocessing.Pool使用的方法。 您可以在此处将None用作哨兵:

def foo(*args):
    for i in range(3):
        queue = args[0]
        queue.put(os.getpid())
    queue.put(None)

...

while items:
    for proc in tuple(items.keys()):
        queue = items[proc]
        if not queue.empty():
            r = queue.get()
            print(r)
            if r is None:
                proc.join()
                del items[proc]
    time.sleep(0.1)

一个有效的解决方案在下面发布。 该方法不是使用Process.run运行proc,而是使用multiprocessing.pool.ThreadPool.map_async方法启动进程而不会阻塞。 然后,使用multiprocessing.Queue对象存储可由MainProcess运行的foo函数访问的数据。

import time, multiprocessing, Queue
from multiprocessing.pool import ThreadPool
logger = multiprocessing.log_to_stderr()

def foo(args):
    queue = args[0]
    arg = args[1]
    for i in range(3):
        time.sleep(2)
        queue.put([arg, time.time()])

pool = ThreadPool(processes=4)
queue = multiprocessing.Queue()
map_result = pool.map_async(foo, [(queue, arg) for arg in range(3)])

logger.warning("map_result: %s" % map_result) 

map_result.wait(timeout = 10) 
if not map_result.ready():
    message = '%s is timed out and terminated.' % pool 
    log.error(message)
    pool.terminate()
    raise Exception(message)

while not queue.empty():
    if queue.empty():
        break
    logger.warning("queue_data: %r" % queue.get(True, 0.1))  

pool.close()
pool.join()
#encoding:utf-8

from multiprocessing import Pool, Manager

def tiny(q, j):
    if len(j) < 100:
        q.put(j+j[-1])
    print " Done!", j
    q.put(-1)
    return

queue = Manager().Queue()
pool = Pool(processes=10)
pool.apply_async(tiny, (queue, "A"))
pool.apply_async(tiny, (queue, "B"))
pool.apply_async(tiny, (queue, "C"))

created = 3
fininshed = 0

while created > fininshed:
        i = queue.get(True, None)
        if isinstance(i, int):
            fininshed += 1
        else:
            created += 1
            pool.apply_async(tiny, (queue, i))

pool.close()
pool.join()
print [worker.is_alive() for worker in pool._pool]

暂无
暂无

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

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