3 ms·
> can one construct a model of function calling that makes one not have to care about async vs. sync functions at the cost of something else? If I understand i
by enragedcacti 2y ago
> can one construct a model of function calling that makes one not have to care about async vs. sync functions at the cost of something else?
If I understand it correctly this is technologically possible in Python and there are two main tradeoffs depending on how the event loop is modified. given the following:
x = 0
y = 0
async def set_x():
global x
x = await request_x() # returns 5
async def set_y()
global y
y = await request_y() # returns 10
def business_logic():
if x == 0:
set_y() # magic synchronous call to async func
print(x + y)
async def do_business():
business_logic()
async def main():
await asyncio.gather(
set_x(),
do_business())
What is the value that's printed? If all coroutines share the same event loop then we don't know because set_y() could yield execution and give it to set_x(). The author of business_logic() may not even know they are writing async code because it just works, and the author of main() assumes that do_business() is concurrency safe because it's async.
The alternative is nested event loops, so everything in business_logic() gets its own event loop that must fully complete before anything else in the parent event loop can run. This solves the concurrency bug but we've introduced blocking into code that was obviously intended to be async. This approach works (see nest-asyncio package) but the core devs have opted against it because they feel it makes it too easy to break the value of async on accident or out of laziness.
IMO something that could work is a `sync def` declaration where the function is written in async style but gets its own event loop and can be called synchronously. It solves the tainting issue while still being explicit, easy to convert to full async, and easy to lint for in projects where it would be a net negative.