Remix.run Logo
bre1010 3 hours ago

I wish the key word was instead dontawait and was used inversely to how await is used. 99% of the time I'm using an async function, despite however slow it is, there's nothing for my code to do but wait for it to finish. But if for some reason I would like the next line of code to run before the current one is done, I'll let you know.

Like, why can't my sync function await something asynchronous? If it has to lock up the whole thread while that function executes, that's fine because that's how it was going to work anyway 99% of the time

SatvikBeri 13 minutes ago | parent | next [-]

Julia does this – you generally write synchronous, single-threaded functions most of the time, and can use code like `t = @spawn foo(b)` to get a Task, and then `output = fetch(t)` to wait for it and get the value.

I like this general approach a lot, it's overall quite nice for Julia's core use case of number crunching, it means you typically make decisions around concurrency at the call sites. Though it does rely heavily on Julia's runtime, and it can be a bit difficult to figure out what's going on under the hood.

enragedcacti 2 hours ago | parent | prev | next [-]

> Like, why can't my sync function await something asynchronous?

The answer, at least for Python, is that it is an intentional limitation because the alternatives introduce some quite bad trade-offs.

Option 1: your awaited promise goes into the main async event loop. This is bad because it means that your single-threaded sync function now needs to be thread-safe, and so does any sync code that calls your sync function despite it not even knowing that you're doing anything async. This is essentially unworkable without throwing away the option of writing non-thread-safe code.

Option 2: Your awaited promise goes into its own new event loop that only contains sibling and child promises. There's nothing technically stopping someone from doing this[1], but now you've lost a ton of the value of async because you will inevitably end up with a ton of siloed event loops that leave the process idle despite other async tasks existing that could run. Effective async code needs to share an event loop at as high of a level as possible, which means tainting as many methods with async as possible. At that point, you might as well enforce it at the language level and avoid the inevitable pain and fragmentation that comes from other devs across the ecosystem mixing sync and async code.

[1] https://pypi.org/project/nest-asyncio/

As explained by Guido: https://github.com/python/cpython/issues/66435#issuecomment-...

zokier 2 hours ago | parent [-]

I think the downsides of option 2 are overstated here. In lots of cases you don't care about the "value of async", you just want code that works well enough and option 2 does accomplish that in anything that is not perf critical.

enragedcacti 2 hours ago | parent [-]

I agree in isolation, and I have used nest-asyncio a couple of times where it really was a lot easier than the alternative, but from an ecosystem perspective I'm glad it isn't the default. Most of the time someone wants to do this it's a junior trying to work around a non-issue (e.g copy-pasting from a guide that includes asyncio.run()), and the trade-off is a massively increased surface for performance footguns throughout your code base and all the libraries you use. Linters could save you from the first case but it would be a lot more work to profile, track down, and fix spots in all your dependencies that cause your event loop to get fragmented.

sheept 2 hours ago | parent | prev | next [-]

At least in JavaScript, it's nice to be able to see explicitly where you can expect the function to yield, so it's clear when race conditions can occur, or if you're calling it in a loop, whether you should consider running things in parallel.

Plus, you probably don't want to lock up the whole thread if you're writing anything more than a quick script, like a web server or a GUI.

axus 2 hours ago | parent | prev [-]

Like the & at the end of a shell command?