当两个异步任务访问同一个可等待对象时安全吗?

2024-10-03 11:20:56 发布

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

简单地说,thread-safe意味着当多个thread访问同一个资源时,它是安全的,我知道Asyncio基本上使用一个thread。在

但是,不止一个Asyncio Task可以像multi-threading那样一次多次访问一个资源。在

例如DB connection(如果对象不是thread-safe,并且支持Asyncio操作)。在

  1. 调度Task A和{}访问同一个DB对象。在
  2. IO循环执行Task A。在
  3. Task Aawait对DB对象执行IO操作。(这将花费足够长的时间)
  4. IO循环执行Task B
  5. Step3的IO操作仍在进行中(未完成)。在
  6. Task Bawait对同一DB对象执行IO操作。在
  7. 现在,Task B正试图一次访问同一对象。在

它在Asyncio中是完全安全的吗?如果是,它又有什么安全性?在


Tags: 对象ioasynciotaskdb时间资源connection
2条回答

从多个任务使用同一个asyncio对象通常是安全的。例如,aiohttp有一个session对象,多个任务应该“并行”访问同一个会话。在

if so, what does it make safe?

asyncio的基本架构允许多个协程来await一个单独的未来结果-它们将简单地全部订阅未来的完成,并且所有的都将被调度在结果准备好之后运行。这不仅适用于协同程序,也适用于使用add_done_callback订阅未来的同步代码。在

这就是asyncio将如何处理您的场景:任务A和B最终将订阅DB对象和等待的某个未来。一旦结果可用,它将依次传递给他们两个。在

通常与多线程编程相关的陷阱不适用于asyncio,因为:

  • 与线程不同,上下文切换的位置是非常可预测的——只需查看代码中的await语句(以及async with和{}-但这些仍然是非常可见的关键字)。他们之间的任何东西,无论出于什么目的,都是原子的。这样就不需要同步原语来保护对象,也消除了由于错误处理这些工具而导致的错误。

  • 所有对数据的访问都是从运行事件循环的线程进行的。这就消除了并发写入的共享内存的数据争用的可能性。

多任务处理可能失败的一种情况是多个使用者附加到同一个流式资源。例如,如果多个任务试图在同一个reader流上等待reader.read(n),那么其中一个任务将获得新数据1,而其他任务将一直等待,直到新数据到达。这同样适用于任何共享流资源,包括多个对象共享的文件描述符或生成器。即使这样,其中一个任务也能保证获得数据,流对象的完整性也不会以任何方式受到损害。在


1只有当任务共享读卡器并且每个任务分别调用data = await reader.read(n)时,一个接收数据的任务才适用。如果要使用fut = reader.read(n)不带使用await)提取一个未来,那么在多个任务中共享未来,并用data = await fut在每个任务中等待它,则所有任务都将收到由该未来返回的特定数据块的通知。

不,asyncio不是线程安全的。通常只有一个线程可以控制事件循环和/或与事件循环关联的资源。如果其他线程想访问它,它应该通过特殊的方法来访问它,比如call_soon_threadsafe。在

相关问题 更多 >