差异的核心原因在于线程(和进程)如何处理块与coroutines处理阻塞事件的方式.在线程中,当前线程被挂起,直到任何条件结束并且线程可以继续.例如,在期货的情况下,如果您请求未来的结果,可以暂停当前线程直到该结果可用.
但是,事件循环的并发模型不是暂停代码,而是返回事件循环并在准备好后再次调用.因此,请求未准备好结果的asyncio future的结果是错误的.
你可能会认为asyncio的未来可能只是等待,虽然这样效率很低,你的协程会阻止它真的那么糟糕吗?事实证明,拥有协程块很可能意味着未来永远不会完成.很可能未来的结果将由与运行请求结果的代码的事件循环相关联的一些代码设置.如果运行该事件循环的线程阻塞,则不会运行与事件循环关联的代码.因此阻塞结果会导致死锁并阻止生成结果.
所以,是的,界面的差异是由于这种固有的差异.举个例子,你不希望在concurrent.futures服务器抽象中使用asyncio future,因为这会阻塞事件循环线程.
add_done_callbacks差异保证了回调将在事件循环中运行.这是可取的,因为他们将获得事件循环的线程本地数据.此外,许多协程代码假定它永远不会与来自同一事件循环的其他代码同时运行.也就是说,在假设来自同一事件循环的两个协同程序不同时运行的情况下,协程只是线程安全的.在事件循环中运行回调可以避免许多线程安全问题,并且可以更容易地编写正确的代码.