当不同事件循环中的协程访问通用代码时,是否需要使用asyncio.Lock?

问题描述

背景

我继承了使用多个事件循环来处理对使用websockets.serve创建的多个对象的读写的代码。这些协程需要访问公共列表。

场景

  • 事件循环X中的协程A
  • 事件循环Y中的协程B

问题

  1. 我需要保护对公用列表的访问吗?
  2. 如果我确实需要保护对列表的访问,那么asyncio.Lock()是否足够?

解决方法

我假设事件循环是并行运行的,每个循环都在其自己的线程中。在这种情况下,您将完全像对待不同线程之间共享的数据那样对待共享数据。具体来说:

  1. 这取决于您对列表的处理方式。如果一个线程正在读取而另一个线程正在调用类似append的线程,则您不需要同步,因为您受到了GIL的保护。但是,如果您正在做更复杂的事情,例如删除读取器线程指示的项目,您将需要锁定以确保不会因并发修改而丢失项目。

  2. asyncio.Lock绝对不是不是正确使用的锁定设备,因为它是为在一个事件循环(即单线程)中使用而设计的。您也不能使用threading.Lock,因为它是非异步的并且会阻塞整个事件循环。您可能可以使用loop.call_soon_threadsafe在事件循环之间进行同步,但这并不简单。

您继承的代码使用asyncio的方式不适合您使用,并且您很可能会遇到问题。由于asyncio事件循环旨在扩展到任意数量的任务,因此我建议将代码重构为使用单个事件循环。然后,您将不需要特殊的同步,因为等待之间的任何代码自然会形成一个关键部分,并且如果您需要在等待之间进行锁定,则可以使用针对该用例创建的asyncio.Lock

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...