Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to run async function using exec?

I am trying to call an async function from exec, I would expect it to work like:

def test():
    print("test")
    exec('def test2():\n    print("test")\ntest2()')
test()

Output:

test
test

So a function defined in exec is able to call itself, however we can't do such things in asyncio as:

async def test():
    print("test")
    exec('async def test2():\n    print("test")\nawait test2()')

We cant use await outside function as well as we cant call another loop from a running loop:

async def test():
    print("test")
    exec('async def test2():\n    print("test")\nasyncio.run(test2())')

Is there any solution to this problem?

like image 408
Strings Avatar asked Nov 29 '25 08:11

Strings


2 Answers

You can put current running loop as exec() global parameter:

import asyncio


async def test():
    print("test")
    loop = asyncio.get_running_loop()
    exec('async def test2():\n    print("test2")\nloop.create_task(test2())', {'loop': loop})

asyncio.run(test())

Prints:

test
test2

EDIT: To run asynchronously, you can return awaitable from the exec():

import asyncio

async def some_other_task():
    await asyncio.sleep(1)
    print('some_other_task')

async def test():
    loop = asyncio.get_running_loop()
    t = [None]

    exec('async def test2():\n    await asyncio.sleep(3);print("task in exec finished")\nt[0] = loop.create_task(test2())', {'asyncio': asyncio, 'loop': loop, 't': t})
    await asyncio.gather(some_other_task(), t[0])

asyncio.run(test())

Prints:

some_other_task           # <-- after 1 sec
task in exec finished     # <-- after 3 sec
like image 193
Andrej Kesely Avatar answered Dec 01 '25 20:12

Andrej Kesely


Not possible. You would need some kind of "asynchronous exec" capable of suspending its own execution, and Python's syntax would need to support await outside an asynchronous function definition. Without that, there's no way for exec to return control to the event loop when it needs to suspend.

Andrej Kesely's answer does not work. It does not actually run the coroutine. It only arranges for the coroutine to run later.

like image 42
user2357112 supports Monica Avatar answered Dec 01 '25 21:12

user2357112 supports Monica



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!