运行时错误:此事件循环已在 python 中运行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46827007/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
RuntimeError: This event loop is already running in python
提问by wvxvw
I think I'm getting this error because my code calls asyncio.get_event_loop().run_until_complete(foo())
twice. Once from foo()
and second time from function called by foo()
. My question is then: why should this be a problem? Why should I even care that this loop is running?
我想我收到这个错误是因为我的代码调用了asyncio.get_event_loop().run_until_complete(foo())
两次。一次 fromfoo()
和第二次 from 调用的函数foo()
。我的问题是:为什么这会成为一个问题?为什么我还要关心这个循环是否正在运行?
There was an edit made to this question which, I think, obscured it (some people prefer to follow rules without understanding them, thus an "illegal" word was removed from the title). Unfortunately, this creates confusion.
对这个问题进行了编辑,我认为它掩盖了它(有些人喜欢在不理解规则的情况下遵守规则,因此从标题中删除了“非法”一词)。不幸的是,这会造成混乱。
I'm not surprised by the fact that the error is raised. I can trace it back to the asyncio
source and see that the authors of this library wanted to do it this way, there's no mystery there. The puzzling part is in the reason the authors of the library decided it's illegal to ask from event loop to run some function to completion when the loop is already running.
我对出现错误这一事实并不感到惊讶。我可以追溯到asyncio
源头,看到这个库的作者想要这样做,这没有什么神秘之处。令人费解的部分是该库的作者认为在循环已经运行时从事件循环中要求运行某个函数直到完成是非法的。
We can reduce the problem to just two such calls, and through case analysis we will see that these are the three possibilities:
我们可以将问题简化为两个这样的调用,通过案例分析我们将看到这三种可能性:
- Neither of both functions ever terminates.
- One of the functions eventually terminates.
- Both functions eventually terminate.
- 这两个函数都不会终止。
- 其中一项功能最终终止。
- 这两个函数最终都会终止。
Now, is there any sane behavior which would address all three cases? To me, it is obvious that there is, or, perhaps are multiple sane behaviors possible here. For example:
现在,是否有任何理智的行为可以解决所有三种情况?对我来说,很明显,这里可能有多种理智的行为。例如:
- Nothing special, the execution of both functions is interleaved, and they keep running forever, just as expected.
- The loop doesn't return control to the code following the first instance of
run_until_complete()
until second function completes (thus no code afterrun_until_complete()
will be executed. - After the last function terminates, the loop returns control to the first code object which invoked
run_until_complete
ignoring all other invocation sites.
- 没有什么特别的,这两个函数的执行是交错的,并且它们永远运行,正如预期的那样。
- 循环不会将控制权返回给第一个实例之后的代码,
run_until_complete()
直到第二个函数完成(因此不会run_until_complete()
执行之后的代码。 - 在最后一个函数终止后,循环将控制返回到第一个代码对象,该对象调用
run_until_complete
忽略所有其他调用站点。
Now, I can understand that this behavior may not be something that everyone would want. But, since this library decided to give programmers control over starting / stopping the event loop, it should also meet the consequences of such decisions. Making it an error to start the same loop multiple times precludes library code from ever doing this, which reduces the quality and usefulness of libraries utilizing asyncio
(which is indeed the case with, for example, aiohttp
).
现在,我可以理解这种行为可能不是每个人都想要的。但是,由于该库决定让程序员控制启动/停止事件循环,因此它也应该满足此类决定的后果。多次启动同一个循环是错误的,这会阻止库代码执行此操作,这会降低库使用的质量和实用性asyncio
(例如,确实就是这种情况aiohttp
)。
回答by Mikhail Gerasimov
Event loop running - is an entry point of your async program. It manages running of all coroutines, tasks, callbacks. Running loop while it's running makes no sense: in some sort it's like trying to run job executor from same already running job executor.
事件循环运行 - 是异步程序的入口点。它管理所有协程、任务、回调的运行。在运行时运行循环是没有意义的:在某种意义上,它就像试图从同一个已经运行的作业执行程序中运行作业执行程序。
Since you have this question, I guess you may misunderstand a way how asyncio works. Please, read this article- it's not big and gives a good introduction.
既然你有这个问题,我想你可能误解了 asyncio 的工作方式。请阅读这篇文章- 它并不大,并提供了很好的介绍。
Upd:
更新:
There's absolutely no problem in adding multiple things to be ran by event loop while this loop is already running. You can do it just by awaiting for it:
当这个循环已经在运行时,添加多个要由事件循环运行的东西绝对没有问题。你可以通过等待它来做到这一点:
await coro() # add coro() to be run by event loop blocking flow here until coro() is finished
or creating a task:
或创建任务:
asyncio.ensure_future(coro()) # add coro() to be run by event loop without blocking flow here
As you can see you don't need call event loop's methods to make something being ran by it.
正如你所看到的,你不需要调用事件循环的方法来运行它。
Event loop's method such as run_forever
or run_until_complete
—?are just a?ways to?start event loop in?general.
事件循环的方法,例如run_forever
或run_until_complete
—?一般来说只是启动事件循环的一种方法。
run_until_complete(foo())
means: "add foo()
to be ran by event loop and run event loop itself until foo()
isn't done".
run_until_complete(foo())
意思是:“添加foo()
由事件循环运行并运行事件循环本身直到foo()
未完成”。
回答by Ovidiu Ionut
I got the issue resolved by using the nest_async
我通过使用 nest_async 解决了这个问题
pip install nest_asyncio
and adding below lines in my file.
并在我的文件中添加以下几行。
import nest_asyncio
nest_asyncio.apply()
回答by nurettin
I'm writing this down not to patronize, but to explain how we can handle the situation where simply queueing async functions and awaiting their results synchronously while the event loop is running, doesn't work.
我写下这个不是为了光顾,而是为了解释我们如何处理在事件循环运行时简单地将异步函数排队并同步等待它们的结果不起作用的情况。
run_until_complete
is not for running any number of arbitrary async functions synchronously, it is for running the main entry point of your entire async program. This constraint is not immediately apparent from the docs.
run_until_complete
不是用于同步运行任意数量的任意异步函数,而是用于运行整个异步程序的主要入口点。这个限制在文档中并不明显。
Since libraries like aiohttp will queue it's own entry point to run as a server and block the loop's synchronous operations using run_until_complete
or run_forever
, the event loop will already be running and you won't be able to run independent synchronous operations on that event loop and wait for it's result within that thread.
由于像 aiohttp 这样的库会将它自己的入口点排队以作为服务器运行并使用run_until_complete
or阻止循环的同步操作run_forever
,因此事件循环已经在运行,您将无法在该事件循环上运行独立的同步操作并等待它是该线程内的结果。
That being said, if you have to queue an async operation into a running event loop from within a sync context and get it's result like a regular function, that may not be possible. Your best bet is to pass in a synchronous callback to be called once the async operation finishes. That will of course slow down your event loop.
话虽如此,如果您必须从同步上下文中将异步操作排队到正在运行的事件循环中,并像常规函数一样获得它的结果,那可能是不可能的。最好的办法是传入一个同步回调,以便在异步操作完成后调用。这当然会减慢你的事件循环。
Another way of handling the situation is to execute your code within startup and cleanup callbacks of the async http library you're using. Here's a sampleof how you may accomplish this.
处理这种情况的另一种方法是在您正在使用的异步 http 库的启动和清理回调中执行您的代码。下面是一个示例,说明您可以如何实现这一点。
回答by Diaf Badreddine
Just add this bunch of code in the beginning
一开始就加这一堆代码
!pip install nest_asyncio
import nest_asyncio
nest_asyncio.apply()