Python - 如何安排ThreadPoolExecutor?

时间:2018-04-23 06:08:24

标签: python multithreading queue

我正在使用concurrent.futures.ThreadPoolExecutor Queue,代码是这样的:

from concurrent.futures import ThreadPoolExecutor
from queue import Queue

def func(parent):
    return parent//2, parent//2, parent<=2

def worker(parent, q):
    child1, child2, end = func(parent)
    print(parent) 
    if not end:
        q.put(child1)
        q.put(child2)

if __name__ == "__main__":
    q = Queue()
    q.put(100)
    executor = ThreadPoolExecutor(max_workers=6)
    while True:
        parent = q.get()
        future = executor.submit(worker, parent, q)
        if q.empty() and future.done():
            break

此代码的问题是future.done()永远不会为True,我无法摆脱这个无限while循环。

我的预期结果是等到没有什么可以处理的。即队列是空的,并且所有工作人员都完成了他们的工作,没有任何进一步的东西被放入这个队列。然后我可以停止这个循环并做其他事。

P.S。我使用的实际func比上面的例子更复杂,但问题是一样的。

1 个答案:

答案 0 :(得分:1)

你的问题是你没有足够的耐心:对executor.submit的调用会立即返回,即使对worker的隐含调用没有发生 - 这正是异步构造的要点像期货一样。因此,当您事后直接检查future.done()时,很有可能在执行者有时间执行worker之前执行此检查,这意味着您的未来尚未完成。

您可以通过在调用submitif声明之间插入以下代码来验证这一点:

import time
time.sleep(0.1)

这确实可以实现您的目标,但它并不能以优雅的方式真正解决您的问题。

仔细观察,问题在于您的计划任务可能会生成新任务,并且您只知道他们是否在完成任务后这样做了。这意味着您必须等到刚刚安排的任务执行,然后才能决定是否停止安排新任务:

if __name__ == "__main__":
    q = Queue()
    q.put(100)
    with ThreadPoolExecutor(max_workers=6) as executor:
        while not q.empty():
            parent = q.get()
            future = executor.submit(worker, parent, q)
            future.result()  # Wait for task

还要确保调用Executor.shutdown,或者更好地在上下文管理器中使用执行程序(如上所示),以便在完成后正确释放所有资源。