4 ms·
async/await are coroutines and continuations (bear with me). Here is synchronous code: result = server.getStuff() print(result) Here is synchronous c
by cheez 7y ago
async/await are coroutines and continuations (bear with me).
Here is synchronous code:
result = server.getStuff()
print(result)
Here is synchronous code, that tries to be asynchronous:
server.getStuff(lambda result: print(result))
Once server.getStuff returns, the callback passed to it is called with the result.
Here is the same code with async/await:
result = await server.getStuff()
print(result)
Internally, the compiler rewrites it to (roughly) the second form. That's called a continuation.
That's pretty much it.
A more involved example.
Synchronous code:
result = server.getStuff()
second = server.getMoreStuff(result+1)
print(result)
Synchronous code that tries to be asynchronous:
server.getStuff(
lambda result: server.getMoreStuff(
result+1,
lambda result2: print(result2)
))
A lot of JS code used to look like this hideous monstrosity.
Async/await version:
result = await server.getStuff()
second = await server.getMoreStuff(result+1)
print(result)
Remember again, that it is basically transformed by the compiler into the second form.
- arcticbull 7y agoThis is an incredibly helpful explanation. I went from not really knowing what all this mumbo jumbo was about to a useful mental model. Cheers!
- 2bitencryption 7y agoThanks. Helpful. My question is, in this example: result = await server.getStuff() second = await server.getMoreStuff(result+1) print(result) `await getStuff()` MUST terminate before `await getMoreStuff() ` begins. So this chunk alone is analagous to synchronous code, unless we're in the middle of a spawned task, and there are other spawned tasks in the executor that can be picked up.
- csande17 7y agoYup, your understanding is correct. That code behaves equivalently to the synchronous version, and the only benefit is that the thread can run other tasks while it's waiting for the getStuff() and getMoreStuff() to come back. Async/await is really popular in the JavaScript community because in web apps, you usually only have a single thread of execution which you share with the browser UI code. So if your code made a network request synchronously, the user might not be able to scroll or click links or anything until it finished.
- simcop2387 7y agoCorrect, if there's nothing else that can be picked up it'll behave essentially the same as the non-async code. But it'll mean that adding other things to be done at a later stage is much much easier than trying to do so without it.
- lenkite 7y agoYes, the idea is that the thread that is executing this piece of code can "steal" other work when it is awaiting on either of those methods. Frankly, in the case of sequential flow like the above, I would rather write result = server.getStuff() second = server.getMoreStuff(result+1) print(result) and have the runtime automatically perform work-stealing for me. No need for awaits. They just litter the code. This is what Go does.
- pjmlp 7y agoThus the FFI impact on Go when going over language boundary and workarounds like runtime.LockThread().
- littlestymaar 7y agoIn Go you need to manually tell the runtime to spawn a goroutine with the `go` keyword, which also «litter» the code…
- bsaul 7y agoExcept in practice, go keyword is used much more coarsly and sparingly because you can group all the block of function calls under one big go call. With async, every single function has to be flagged as beeing asynchronous and be called differently ( although maybe some modern languages have a way to group all the await calls ?)
- littlestymaar 7y agoThat's funny how gophers can at the same time defend the «explicitness» of the if-based error handling, and be annoyed to have syntactic annotations for the yield points for coroutines (because that's exactly what `await` is, versus the yield points silently added by the go compiler everywhere so the runtime can perform its scheduling).
- bsaul 7y agonot sure who you're refering to.. i certainly don't like many aspects of the go language. goroutines and the "go" keyword isn't one of them.
- jnbiche 7y agoI don't understand your examples of "Synchronous code that tries to be asynchronous". In fact, the examples you provided are of asynchronous code being...asynchronous. Callbacks are asynchronous (or to be fully correct, I should say that they allow one to program asynchronously, which is exactly what async/await does). Indeed, since you mention continuations, I'm sure you realize that they're more or less callbacks.
- z3t4 7y agoserver.getStuff(gotStuff) server.getMoreStuff(gotMoreStuff) Just using functions is more simple and also more powerful. A function being async usually means stuff will happen, things can go wrong, and you might want to do different things depending on the response or whether it failed. Where await is useful though is in serial execution of async functions that really should be sync, but them being async is an optimization in order to not block the thread. It is really unfortunately that so much extra crud had to be introduced to JS (corutines, async, promises) in order to be able to await. Reading complex Promise based code is very unplesent, with async functions pretending to be pure, without any error handling, full of side effects, and omitted returns. With callbacks we had inexperienced programmers writing pyramids of callbacks and if logic. But it was not that bad, as the complexity was in your face, and not hidden under layers of leaky abstraction.