[英]Event loop error in asyncio Lock when instantiated multiple times
I'm running into some strange errors with initialising Locks and running asynchronous code.我在初始化锁和运行异步代码时遇到了一些奇怪的错误。 Suppose we had a class to use with some resource protected by a lock.
假设我们有一个类与一些受锁保护的资源一起使用。
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()
This throws an error when run.这在运行时会引发错误。 It occurs on lock initialisation in
init
.它发生在
init
锁初始化时。
RuntimeError: There is no current event loop in thread 'MainThread'.
运行时错误:线程“MainThread”中没有当前事件循环。
So duplicating the asyncio.run
call in the function does not have this effect.所以在函数中复制
asyncio.run
调用没有这个效果。 It seems that the object needs to be initialised multiple times.似乎该对象需要多次初始化。 It is also not enough to instantiate multiple locks in a single constructor.
在单个构造函数中实例化多个锁也是不够的。 So perhaps it has something to do with the event loops state after
asyncio.run
is called.所以也许它与
asyncio.run
被调用后的事件循环状态asyncio.run
。
What is going on?到底是怎么回事? And how could I modify this code to work?
我如何修改此代码才能工作? Let me also clarify a bit, the instance is created outside
asyncio.run
and async functions for a reason.我还要澄清一下,该实例是在
asyncio.run
和 async 函数之外创建的,这是有原因的。 I'd like for it to be usable elsewhere too.我希望它也能在其他地方使用。 If that makes a difference.
如果这有所作为。
Alternatively, can threading.Lock
be used for async things also?或者,
threading.Lock
可以用于异步事物吗? It would have the added benefit of being thread-safe, which asyncio.Lock
reportedly is not.它将具有线程安全的额外好处,据报道
asyncio.Lock
不是。
What is going on?
到底是怎么回事?
asyncio.Lock()
) it is attached to current event loop and can only be used with itasyncio.Lock()
)时,它会附加到当前事件循环,并且只能与它一起使用asyncio.run()
internally creates new event loop, set it current and close it after finished asyncio.run()
内部创建新的事件循环,将其设置为当前并在完成后关闭它So you're trying to use lock with event loop other than one it was attached to on creation.因此,您尝试将锁定与事件循环一起使用,而不是在创建时附加到的事件循环。 It leads to errors.
它会导致错误。
And how could I modify this code to work?
我如何修改此代码才能工作?
Ideal solution is following:理想的解决方案如下:
import asyncio
async def main():
# all your code is here
if __name__ == "__main__":
asyncio.run(main())
This will guarantee that every async object created is attached to proper event loop asyncio.run
has created.这将保证创建的每个异步对象都附加到
asyncio.run
创建的正确事件循环。
Running event loop (inside asyncio.run
) is meant to be global "entry point" of your async program.运行事件循环(在
asyncio.run
内部)是异步程序的全局“入口点”。
I'd like for it to be usable elsewhere too.
我希望它也能在其他地方使用。
You're able to create an object outside asyncio.run
, but then you should you should move creating async object from __init__
somewhere elsewhere so that asyncio.Lock()
wouldn't be created until asyncio.run() is called .你可以创建一个对象外
asyncio.run
,但你应该你应该摆脱创建异步对象__init__
某处其他地方,这样asyncio.Lock()
不会,直到asyncio.run创建()被调用。
Alternatively, can threading.Lock be used for async things also?
或者, threading.Lock 也可以用于异步事物吗?
No , it is used to work with threads, while asyncio operates coroutines inside a single thread (usually).不,它用于与线程一起工作,而 asyncio 在单个线程内操作协程(通常)。
It would have the added benefit of being thread-safe, which asyncio.Lock reportedly is not.
它将具有线程安全的额外好处,据报道 asyncio.Lock 不是。
In asyncio
you usually don't need threads other than main.在
asyncio
您通常不需要主线程以外的线程。 There're still some reasons to do it, but thread-unsafety of asyncio.Lock
shouldn't be an issue.仍然有一些理由这样做,但是
asyncio.Lock
线程不安全性应该不是问题。
Consider reading following links.考虑阅读以下链接。 It may help to comprehend a situation better:
它可能有助于更好地理解情况:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.