这两种Python代码使用并发执行的功能是等效的吗?

2024-04-24 11:02:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两段代码,代表我正在调试的更复杂的场景。我想知道他们是否在技术上是等价的,如果不是,为什么。你知道吗

第一个:

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表示)。当该操作完成时,我必须执行后续的快速操作。在第一段代码中,我将这些操作放在sync slow操作之后。在第二段代码中,我将其放入回调中。你知道吗

在实现方面,我怀疑未来会创建一个次线程,在次线程中运行代码,这个次线程会在sync slow操作时停止。一旦此操作完成,辅助线程将继续运行,它可以通过执行后续代码或调用回调来继续运行。我认为这两段代码没有区别(除了添加回调允许从外部注入代码这一事实,增加了灵活性),但我可能错了,因此问题来了。你知道吗

请注意,我确实理解,在第一种情况下,当未来仍未解决时调用print,在第二种情况下调用print,但假定状态不相关。你知道吗


Tags: 代码importtimedefresfuturesleepsync
2条回答

https://gist.github.com/mangecoeur/9540178https://docs.python.org/3.4/library/concurrent.futures.html

与concurrent.futures.processPool执行器()作为执行人: 结果=执行者.map(函数,iterable)

你知道吗执行者.map(有趣,[数据]*10)

池=多处理池() 池.map(…)

与并发.futures.ThreadPoolExecutor()作为执行人: 结果=执行者.map(函数,iterable)

这两个例子在事件排序方面并不相等。 让我们看看未来的生命周期。大致上是这样的(从cpython的来源逆向工程):

  • 创造未来
  • 它被添加到执行者的队列中
  • 它是由线程池中的某个空闲/空闲线程从队列中弹出的
  • 提供给submit()的函数在该线程中被调用
  • 未来被标记为已完成
  • future向其所有服务员广播“状态更改”事件
  • 调用回调(仍在同一工作线程中)
  • 工作线程变为空闲/空闲,并可能从队列中获取另一个未来

当您执行语句print(future.result())时,您的主线程阻塞并成为未来的服务员。在future切换到FINISHED之后,但在回调开始执行之前,它就被解除了阻塞。这意味着您无法预测在控制台中打印的第一步是什么-print在任何回调中,或者print(future(result))-它们现在是并行执行的。如果在等待future.result()完成后在回调和主线程中处理相同的数据,则很可能会导致数据损坏。你知道吗

相关问题 更多 >