简体   繁体   English

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

[英]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?到底是怎么回事?

  • When async object is created ( asyncio.Lock() ) it is attached to current event loop and can only be used with it创建异步对象( asyncio.Lock() )时,它会附加到当前事件循环,并且只能与它一起使用
  • Main thread have some default current event loop (but other threads you create won't have default event loop)主线程有一些默认的当前事件循环(但你创建的其他线程不会有默认的事件循环)
  • 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.

相关问题 Kivy Python Scrollview 事件在 class 实例化多次时失败 - Kivy Python Scrollview event misfiring when in a class instantiated multiple times Asyncio 锁在事件循环结束时获取任务 - Asyncio lock acquire task at end of event loop 每个python进程的Asyncio事件循环(aioprocessing,多个事件循环) - Asyncio event loop per python process (aioprocessing, multiple event loops) 在 asyncio 事件循环中运行 .render()(来自 requests_html)时,出现错误“此事件循环已在运行” - When running .render() (from requests_html) in an asyncio event loop, I get the error 'This event loop is already running' Asyncio循环等待事件 - Asyncio in loop waiting for event 何时使用 asyncio.get_running_loop() 与 asyncio.get_event_loop()? - When to use asyncio.get_running_loop() vs asyncio.get_event_loop()? 异步期间“运行时错误事件循环已在运行” - “Runtime error event loop already running” during asyncio RuntimeError: 线程 'Thread-1' 中没有当前事件循环,多线程和异步错误 - RuntimeError: There is no current event loop in thread 'Thread-1' , multithreading and asyncio error 结合 asyncio 和 aiohttp 时出现“RuntimeError:此事件循环已在运行” - "RuntimeError: This event loop is already running" when combine asyncio and aiohttp 跟随 asyncio.run() 时 asyncio.get_event_loop() 失败 - asyncio.get_event_loop() fails when following asyncio.run()
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM