<p>从多个任务使用同一个asyncio对象通常是安全的。例如,aiohttp有一个session对象,多个任务应该“并行”访问同一个会话。在</p>
<blockquote>
<p>if so, what does it make safe?</p>
</blockquote>
<p>asyncio的基本架构允许多个协程来<code>await</code>一个单独的未来结果-它们将简单地全部订阅未来的完成,并且所有的都将被调度在结果准备好之后运行。这不仅适用于协同程序,也适用于使用<code>add_done_callback</code>订阅未来的同步代码。在</p>
<p>这就是asyncio将如何处理您的场景:任务A和B最终将订阅DB对象和等待的某个未来。一旦结果可用,它将依次传递给他们两个。在</p>
<p>通常与多线程编程相关的陷阱不适用于asyncio,因为:</p>
<ul>
<li><p>与线程不同,上下文切换的位置是非常可预测的——只需查看代码中的<code>await</code>语句(以及<code>async with</code>和{<cd5>}-但这些仍然是非常可见的关键字)。他们之间的任何东西,无论出于什么目的,都是原子的。这样就不需要同步原语来保护对象,也消除了由于错误处理这些工具而导致的错误。</p></li>
<li><p>所有对数据的访问都是从运行事件循环的线程进行的。这就消除了并发写入的共享内存的数据争用的可能性。</p></li>
</ul>
<p>多任务处理可能失败的一种情况是多个使用者附加到同一个流式资源。例如,如果多个任务试图在同一个<code>reader</code>流上等待<code>reader.read(n)</code>,那么其中一个任务将获得新数据<sup>1</sup>,而其他任务将一直等待,直到新数据到达。这同样适用于任何共享流资源,包括多个对象共享的文件描述符或生成器。即使这样,其中一个任务也能保证获得数据,流对象的完整性也不会以任何方式受到损害。在</p>
<p/><hr/>
<sup>1</sup>只有当任务共享读卡器并且每个任务分别调用<code>data = await reader.read(n)</code>时,一个接收数据的任务才适用。如果要使用<code>fut = reader.read(n)</code>(<em>不带</em>使用<code>await</code>)提取一个<em>未来</em>,那么在多个任务中共享未来,并用<code>data = await fut</code>在每个任务中等待它,则所有<em>任务都将收到由该未来返回的特定数据块的通知。