多次实例化时 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
的线程不安全应该不是问题。
考虑阅读以下链接。这可能有助于更好地理解情况:
我 运行 在初始化锁和 运行 异步代码时遇到了一些奇怪的错误。假设我们有一个 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
的线程不安全应该不是问题。
考虑阅读以下链接。这可能有助于更好地理解情况: