我有两段代码,代表我正在尝试调试的更复杂的场景。我想知道它们在技术上是否等效,如果不是,为什么。
第一个:
import time
from concurrent.futures import ThreadPoolExecutor
def cb(res):
print("done", res)
def foo():
time.sleep(3)
res = 5
cb(res)
return res
with ThreadPoolExecutor(max_workers=2) as executor:
future = executor.submit(foo)
print(future.result())
第二个:
def cb2(fut):
print("done", fut.result())
def foo2():
time.sleep(3)
return 5
with ThreadPoolExecutor(max_workers=2) as executor:
future = executor.submit(foo2)
future.add_done_callback(cb2)
print(future.result())
问题的核心是:我需要调用一个sync,运行缓慢(这里用sleep表示)。该操作完成后,我必须执行后续的快速操作。在第一个代码中,我将这些操作紧跟在同步慢速操作之后。在第二个代码中,我把它放在回调中。
在实现上,我怀疑 future 会创建一个副线程,在副线程中运行代码,这个副线程会停在sync slow操作上。完成此操作后,辅助线程将继续运行,它可以通过执行后续代码或调用回调来继续运行。我看不出这两段代码有什么区别(除了添加回调允许从外部注入(inject)代码这一事实之外,增加了灵 active ),但我可能是错的,因此出现了这个问题。
请注意,我确实理解在第一种情况下,当 future 仍未解决时调用打印,而在第二种情况下,它被调用,但假设状态不相关。
最佳答案
这两个示例在事件排序方面并不相同。 让我们来看看 Future 的生命周期。大致是这样的(从 cpython 的源代码逆向工程):
- 创造了 future
- 它被添加到执行者的队列中
- 它被线程池中的一些空闲/空闲线程从队列中弹出
- 提供给
submit()
的函数在该线程中被调用 - future 被标记为已完成
- future 向所有服务员广播“状态改变”事件
- 调用回调(仍在同一个工作线程中)
- 工作线程变为空闲/空闲,并可能从队列中获取另一个 future
当您执行语句 print(future.result())
时,您的主线程会阻塞并成为 future 的等待者。在 future 切换到 FINISHED 之后,但在回调开始执行之前,它会立即解除阻塞。这意味着您无法预测控制台中的打印先行 - print
在任何回调中,或 print(future(result))
- 它们现在并行执行.如果您在等待 future.result()
完成后在回调和主线程中处理相同的数据,则可能会损坏数据。
关于python - 这两个 python 代码是否等同于使用并发 future ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57523440/