uasyncio : missing RuntimeError: This event loop is already running
I've just spent far too long debugging, what is essentially the following code:
#!/usr/bin/env python
try:
import asyncio
except ImportError:
import uasyncio as asyncio
loop = asyncio.get_event_loop()
async def foo():
print('foo()')
async def main():
loop.run_until_complete(foo())
while True:
print('app_loop()')
await asyncio.sleep(1)
if __name__ == '__main__':
loop.run_until_complete(main())
I know what you're thinking.... why run_until_complete inside an async function.
I completely agree, and now that I have the root cause, it's easy to fix.
However: this was nested inside a relatively large code-base, and I had no trace-back leading me to the root cause.
Finding this required a lot of cutting code until the problem went away, which wasn't helped by it being in 2 places.
Run on CPython
When run on Python 3.9.9, it raises.
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/usr/lib/python3.9/asyncio/base_events.py", line 647, in run_until_complete
return future.result()
File "<stdin>", line 2, in main
File "/usr/lib/python3.9/asyncio/base_events.py", line 623, in run_until_complete
self._check_running()
File "/usr/lib/python3.9/asyncio/base_events.py", line 583, in _check_running
raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running
Run on micropython
When the above code is executed in micropython I get the following output.
MicroPython v1.17 on 2021-09-02; PYBD-SF6W with STM32F767IIK
Type "help()" for more information.
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== # ... above code pasted here
===
foo()
app_loop()
>>>
Execution took 1 second, no exception raised.
uasyncio Event unexpected behaviour with only one task
[EDIT] Apologies, @kevinkk525 has pointed out that this is a duplcate of https://github.com/micropython/micropython/issues/5843
This prints "start" then runs to completion where I would expect it to wait indefinitely on the Event:
import uasyncio as asyncio
evt = asyncio.Event()
async def main_loop():
while True:
print("start")
await evt.wait()
await asyncio.sleep(1)
print("Got event")
asyncio.run(main_loop())
If an additional task is running the main_loop task behaves as expected, waiting forever:
import uasyncio as asyncio
evt = asyncio.Event()
async def main_loop():
while True:
print("start")
await evt.wait()
await asyncio.sleep(1)
print("Got event")
async def main():
asyncio.create_task(main_loop())
while True:
await asyncio.sleep(1)
asyncio.run(main())