问题描述
背景
我继承了使用多个事件循环来处理对使用websockets.serve创建的多个对象的读写的代码。这些协程需要访问公共列表。
场景
- 事件循环X中的协程A
- 事件循环Y中的协程B
问题
- 我需要保护对公用列表的访问吗?
- 如果我确实需要保护对列表的访问,那么asyncio.Lock()是否足够?
解决方法
我假设事件循环是并行运行的,每个循环都在其自己的线程中。在这种情况下,您将完全像对待不同线程之间共享的数据那样对待共享数据。具体来说:
-
这取决于您对列表的处理方式。如果一个线程正在读取而另一个线程正在调用类似
append
的线程,则您不需要同步,因为您受到了GIL的保护。但是,如果您正在做更复杂的事情,例如删除读取器线程指示的项目,您将需要锁定以确保不会因并发修改而丢失项目。 -
asyncio.Lock
绝对不是不是正确使用的锁定设备,因为它是为在一个事件循环(即单线程)中使用而设计的。您也不能使用threading.Lock
,因为它是非异步的并且会阻塞整个事件循环。您可能可以使用loop.call_soon_threadsafe
在事件循环之间进行同步,但这并不简单。
您继承的代码使用asyncio的方式不适合您使用,并且您很可能会遇到问题。由于asyncio事件循环旨在扩展到任意数量的任务,因此我建议将代码重构为使用单个事件循环。然后,您将不需要特殊的同步,因为等待之间的任何代码自然会形成一个关键部分,并且如果您需要在等待之间进行锁定,则可以使用针对该用例创建的asyncio.Lock
。