0

Here's a simplified scenario for the problem I'm having.

import asyncio

async def c():
    print("yes")

def b():
    asyncio.run(c())

async def a():
    b()

asyncio.run(a())

I'm expecting the program to print "yes". However, I get this instead:

Traceback (most recent call last):
  File [redacted], line 12, in <module>
    asyncio.run(a())
  File "/usr/lib64/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/lib64/python3.7/asyncio/base_events.py", line 579, in run_until_complete
    return future.result()
  File [redacted], line 10, in a
    b()
  File [redacted], line 7, in b
    asyncio.run(c())
  File "/usr/lib64/python3.7/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
sys:1: RuntimeWarning: coroutine 'c' was never awaited

What would you think would be the solution for this problem?

(Also, can this be done using purely asyncio?)

  • 1
    Why do you need to do this? What is your use case as their might be a better solution. – Mohammad Aug 19 '21 at 09:15
  • There is no proper solution for this. Even if you could technically do this, you really, really should not - it will block the outer event loop, voiding any benefit of async even in the best case. – MisterMiyagi Aug 19 '21 at 09:34
  • Please [edit] your question to clarify the constraints of the problem. Right now, the "correct" solution is just to remove b. Does b need the return value of C? Can b be turned into an async function? Does c have to complete during b? Is b required to run in the main thread, and is c required to run in the main event loop? – MisterMiyagi Aug 19 '21 at 09:41
  • This answer explains in great detail: https://stackoverflow.com/questions/55147976/run-and-wait-for-asynchronous-function-from-a-synchronous-one-using-python-async#55170521 – Compro Prasad Jan 27 '23 at 14:00

1 Answers1

-1

Don't call asyncio.run() twice in the same program. Instead, once the event loop is running, create a task and await it. A sync function can create a new task but can't await it; it can return it as an awaitable. The async calling function can then perform the await.

import asyncio

async def c():
    print("yes")

def b():
    return asyncio.create_task(c())

async def a():
    task = b()
    await task

asyncio.run(a())

>>>yes
Paul Cornelius
  • 9,245
  • 1
  • 15
  • 24
  • There is no need for a task here. b could just directly return c(). – MisterMiyagi Aug 20 '21 at 05:22
  • True. But unless there is a second task created somewhere, there is no need for asyncio at all. It seemed to be what the question was asking since there was a second attempt to call run(). – Paul Cornelius Aug 20 '21 at 07:35