0

The purpose of this implementation is to be able to call async functions without the "await" keyword
I have a code that is mixing some sync and async functions, I am calling an async function (B) from a sync function (A) inside an event loop and I am unable to get the return value of the async function. An example as follows:

import asyncio
import time


async def B(x):
    print(f'before_delay {x}')
    await asyncio.sleep(1.0)
    print(f'after_delay {x}')
    return x*x

def A(x):
    task = asyncio.create_task(B(x))
    print(task)
    asyncio.get_event_loop().run_until_complete(task) //did not work
    return 0


async def loop_func():
    res = A(9)
    print(f'after calling function {res}')

async def main():
    while True:
        await loop_func()
        await asyncio.sleep(3.0)

asyncio.run(main())

The error I am getting is quite understandable;
RuntimeError: Cannot run the event loop while another loop is running
The problem is that on my program I have a few loop events already running on the background so I cant use asyncio.run() or run_until_complete (or any other low level functions for that matter)
asyncio.wait() would not work as well and also task.done() is never True.
The expected output is:

>>> before_delay 9
>>> after_delay 9 
>>> 81
>>> after calling function 0
Ofir Ozery
  • 19
  • 5
  • 1
    What you want to do cannot be done. That's because a sync function cannot be suspended and resumed the way an async function can. If you run an async function from a sync function, what's supposed to happen to the sync function when an await is performed? The CPU does not know how to suspend the sync function, run some other task for a while, and then come back and pick up the sync function where it left off. But here's a partial solution: https://stackoverflow.com/questions/69710875/how-can-i-have-a-synchronous-facade-over-asyncpg-apis-with-python-asyncio/69732605#69732605 – Paul Cornelius May 25 '22 at 00:36
  • Thanks for the reply! I saw the solution, as you said it is in sufficient for me. is there another way to accomplish my goal of avoiding the "await" keyword? my motivation is that I am building a development platform that is de-centralized and for that reason uses a lot of async functions - some are blocking and some are not (per our definition) - and I want to allow the developers on my platform to easily distinguish between the two by allowing them to call non-blocking async functions without the "await" thanks again! – Ofir Ozery May 25 '22 at 07:37
  • It can't be done, and I explained the reason. The Python people didn't just add the async keyword in order to irritate you, it's there for a very important reason. Async functions know how to suspend themselves and resume where they left off, like a generator. Sync functions don't. Your problem may be that you've got functions declared async when they don't have to be. If the function doesn't have an await in it, it generally doesn't need to be declared with async def. The only special case I know of is when an API requires a coroutine, in which case you have to give it one. – Paul Cornelius May 26 '22 at 10:40

1 Answers1

0

I would slightly refactor the code. Function A() returns coroutine and loop_func() awaits it. For example:

import asyncio


async def B(x):
    print(f"before_delay {x}")
    await asyncio.sleep(1.0)
    print(f"after_delay {x}")
    return x * x


def A(x):
    async def _wrapper():
        res = await B(x)
        print(res)
        return 0

    return _wrapper()


async def loop_func():
    res = await A(9)
    print(f"after calling function {res}")


async def main():
    while True:
        await loop_func()
        await asyncio.sleep(3.0)


asyncio.run(main())

Prints:

before_delay 9
after_delay 9
81
after calling function 0

...
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
  • Thank you for the reply! Unfortunately using this layout with decorations will not serve my end goal of calling an async function without the "await" keyword. The goal is to do the A(9) call with no keyword assignment – Ofir Ozery May 25 '22 at 08:42