21

I am trying to learn about asyncio for a websockets client. Every piece of code I try gets the following error:

RuntimeError: asyncio.run() cannot be called from a running event loop

I have tried the most simple code and it always gives that RuntimeError. I tried installing the full anaconda distribution again, etc, and can´t find what the problem might be.

I am using Spyder 3.3.3 with Python 3.7.3

An example of code that should work:

import asyncio

async def main():
    print('hello')
    await asyncio.sleep(1)
    print('world')

asyncio.run(main())

Error message:

File "C:\Users\jmart\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 786, in runfile
  execfile(filename, namespace)
File "C:\Users\jmart\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 110, in execfile
  exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Users/jmart/Documents/asynk2.py", line 8, in <module>
  asyncio.run(main())
File "C:\Users\jmart\Anaconda3\lib\asyncio\runners.py", line 34, in run
  "asyncio.run() cannot be called from a running event loop")
RuntimeError: asyncio.run() cannot be called from a running event loop
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Javier Martin
  • 323
  • 1
  • 3
  • 8
  • 4
    Did you try to run the code form a terminal typing `python3.7 asynk2.py`? My guess is that Spyder is using an event loop to run its python console/interpreter which causes this issue... – Bakuriu May 15 '19 at 16:53
  • Many thanks, that seems to be the issue, is there any way to solve this? – Javier Martin May 15 '19 at 17:01
  • 1
    Adding `import nest_asyncio` and `nest_asyncio.apply()` seems to be one solution – Javier Martin May 15 '19 at 17:13
  • Does this answer your question? ["asyncio.run() cannot be called from a running event loop" when using Jupyter Notebook](https://stackoverflow.com/questions/55409641/asyncio-run-cannot-be-called-from-a-running-event-loop-when-using-jupyter-no) – mkrieger1 Sep 07 '22 at 10:39

2 Answers2

28

It's a known problem related to IPython.

One way as you already found is to use nest_asyncio:

import nest_asyncio
nest_asyncio.apply()

The other one is to install older version of tornado:

pip3 install tornado==4.5.3
Mikhail Gerasimov
  • 36,989
  • 16
  • 116
  • 159
  • 1
    The first solution seems to give some running problems for me, installing the older version of tornado seems to work perfectly! – Javier Martin May 15 '19 at 20:39
  • 1
    Beware, nested run calls will starve out loops. This monkey patch is very fragile on python / stdlib upgrades. – Blaze Oct 22 '20 at 13:50
  • 1
    Is there any reason for not simply using [`await main()`](https://stackoverflow.com/a/55409674/1720199) with spyder? – cglacet Apr 05 '21 at 19:11
  • 1
    I've started having problems after upgrading databricks cluster to runtime 11.3 (it informs 3.9.5 on sys.version). My code was working perfectly on 10.5 version. Just added the nest_asyncio as above at the start of my notebook and it's resolved. – munizig Dec 16 '22 at 19:37
8

Problem origin

Spyder runs its own event loop

print(asyncio.get_running_loop().is_running()) 
Returns: True

but only one is allowed per thread

cannot be called when another asyncio event loop is running in the same thread

That is why, when we try to create a new event loop with
asyncio.run(main()) it gives us an error:
RuntimeError: asyncio.run() cannot be called from a running event loop

Solution

Except what already proposed with nest_asyncio and tornado I came up with

  1. Attach to an existing Spyder thread event loop by creating a new task
import asyncio

async def main():
    print('Hello world!')

asyncio.create_task(main())
  1. Create new thread (by executing in external terminal) which allows to run our own event loop.
    Top menu Run -> Run configuration per file... -> Execute in the external system terminal enter image description here

Now the code runs in new terminal and works

import asyncio

async def main():
    print('Hello world!')
asyncio.run(main())

Stepan
  • 504
  • 5
  • 12
  • This is definetly the better answer. Perfect would be a interpreter-independent version with `try: ....create_task(main()) except RuntimeError: asyncio.run(main())`. This works fine in Spyder, but still produces some warnings in python shell :( – PythoNic Feb 17 '21 at 02:43
  • `task = create_task(main())` swallows exceptions. So I added `task.add_done_callback(lambda task: task.result())`. – Joooeey Mar 16 '23 at 12:21