我正在使用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
比上面的例子更复杂,但问题是一样的。
答案 0 :(得分:1)
你的问题是你没有足够的耐心:对executor.submit
的调用会立即返回,即使对worker
的隐含调用没有发生 - 这正是异步构造的要点像期货一样。因此,当您事后直接检查future.done()
时,很有可能在执行者有时间执行worker
之前执行此检查,这意味着您的未来尚未完成。
您可以通过在调用submit
和if
声明之间插入以下代码来验证这一点:
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
,或者更好地在上下文管理器中使用执行程序(如上所示),以便在完成后正确释放所有资源。