多次实例化时 asyncio Lock 中的事件循环错误

Event loop error in asyncio Lock when instantiated multiple times

我 运行 在初始化锁和 运行 异步代码时遇到了一些奇怪的错误。假设我们有一个 class 与一些受锁保护的资源一起使用。

import asyncio

class C:
    def __init__(self):
        self.lock = asyncio.Lock()

    async def foo(self):
        async with self.lock:
            return 'foo'

def async_foo():
    c = C()
    asyncio.run(c.foo())

if __name__ == '__main__':
    async_foo()
    async_foo()

这会在 运行 时引发错误。它发生在 init.

中的锁初始化中

RuntimeError: There is no current event loop in thread 'MainThread'.

所以在函数中复制 asyncio.run 调用没有这种效果。看来该对象需要多次初始化。在单个构造函数中实例化多个锁也是不够的。因此,这可能与调用 asyncio.run 后的事件循环状态有关。

这是怎么回事?我该如何修改这段代码才能工作?让我再澄清一下,实例是在 asyncio.run 之外创建的,异步函数是有原因的。我希望它也可以在其他地方使用。如果这有所作为。

或者,threading.Lock 也可以用于异步操作吗?它将具有线程安全的额外好处,据报道 asyncio.Lock 不是。

What is going on?

  • 创建异步对象时 (asyncio.Lock()) 它附加到 current 事件循环并且只能与其一起使用
  • 主线程有一些默认的当前事件循环(但您创建的其他线程不会有默认的事件循环)
  • asyncio.run() 在内部创建新的事件循环,将其设置为当前并在完成后关闭它

因此,您正在尝试将锁与事件循环一起使用,而不是在创建时附加到它的事件循环。它会导致错误。

And how could I modify this code to work?

理想的解决方案如下:

import asyncio


async def main():
    # all your code is here


if __name__ == "__main__":
    asyncio.run(main())

这将保证创建的每个异步对象都附加到 asyncio.run 已创建的正确事件循环。

运行 事件循环(在 asyncio.run 内)是异步程序的全局 "entry point"。

I'd like for it to be usable elsewhere too.

您可以在 asyncio.run 之外创建一个对象,但是您应该从 __init__ 的某个地方移动创建异步对象 这样 asyncio.Lock()在调用 asyncio.run() 之前不会创建 .

Alternatively, can threading.Lock be used for async things also?

No,它是用来和线程一起工作的,而asyncio是在单线程内部运行协程(通常)。

It would have the added benefit of being thread-safe, which asyncio.Lock reportedly is not.

asyncio 中,您通常不需要 main 以外的线程。仍然有 some reasons 要做,但是 asyncio.Lock 的线程不安全应该不是问题。


考虑阅读以下链接。这可能有助于更好地理解情况: