为什么asyncio.Future与concurrent.futures.Future不兼容?

max*_*max 10 python concurrency python-3.x python-asyncio concurrent.futures

这两个类代表了并发编程的优秀抽象,因此它们不支持相同的API有点令人不安.

具体来说,根据文档:

asyncio.Future几乎兼容concurrent.futures.Future.

区别:

  • result()并且exception()不要采用超时参数并在未来尚未完成时引发异常.
  • 注册的回调add_done_callback()总是通过事件循环调用call_soon_threadsafe().
  • 此类与包中的wait()as_completed()函数不兼容concurrent.futures.

以上列表实际上是不完整的,还有一些差异:

  • running() 方法不存在
  • result()并且exception()可能会提高InvalidStateError,如果叫太早

这些中的任何一个是由于事件循环的固有特性导致这些操作无法实现还是太麻烦而无法实现?

与之相关的差异是什么意思add_done_callback()?无论哪种方式,回调都保证在期货结束后的某个未指定的时间发生,所以这两个类之间是否完全一致?

Mik*_*mov 6

concurrent.futures.Future提供一种通常在使用Executor时在不同线程和进程之间共享结果的方法。

asyncio.Future解决协程的相同任务,但实际上是通常在一个进程/线程中异步运行的某些特殊功能。当前上下文中的“异步”意味着事件循环管理该协程的代码执行流:它可以挂起一个协程内部的执行,开始执行另一个协程,然后返回执行第一个协程-通常所有事情都在一个线程/进程中执行。

这些对象(和许多其他线程 / ASYNCIO对象,如LockEventSemaphore等)看起来很相似,因为并发与线程/进程和协同程序代码的思路是相似的。

我认为对象不同的主要原因是历史性的:asyncio创建时间远晚于threadingconcurrent.futuresconcurrent.futures.Futureasyncio不破坏类API的情况下进行更改可能是不可能的。

两种阶级都应该在“理想世界”中合而为一吗?这可能是值得商榷的问题,但我看到的是许多缺点:当asynciothreading看乍看之下相似,他们在很多方面,包括内部实现或写ASYNCIO /非ASYNCIO码(见的方式非常不同async/ await关键字)。

我认为类别最好可能是最好的:我们清楚地区分了不同的并发方式(即使它们的相似性乍看起来很奇怪)。


Sam*_*man 6

差异的核心原因在于线程(和进程)如何处理块与coroutines如何处理阻塞的事件.在线程中,当前线程被挂起,直到任何条件结束并且线程可以继续.例如,在期货的情况下,如果您请求未来的结果,可以暂停当前线程直到该结果可用.

但是,事件循环的并发模型不是暂停代码,而是返回事件循环并在准备好后再次调用.因此,请求未准备好结果的asyncio future的结果是错误的.

您可能会认为asyncio的未来可能只是等待,虽然这样效率很低,但是你的协程阻止它真的会那么糟糕吗?事实证明,拥有协程块很可能意味着未来永远不会完成.很可能未来的结果将由与运行请求结果的代码的事件循环相关联的一些代码设置.如果运行该事件循环的线程阻塞,则不会运行与事件循环关联的代码.因此阻塞结果会导致死锁并阻止生成结果.

所以,是的,界面的差异是由于这种固有的差异.举个例子,你不希望在concurrent.futures服务器抽象中使用asyncio future,因为这会阻塞事件循环线程.

add_done_callbacks差异保证了回调将在事件循环运行.这是可取的,因为它们将获得事件循环的线程本地数据.此外,许多协程代码假定它永远不会与来自同一事件循环的其他代码同时运行.也就是说,在假设来自同一事件循环的两个协同程序不同时运行的情况下,协程只是线程安全的.在事件循环中运行回调可以避免许多线程安全问题,并且可以更容易地编写正确的代码.