I come from a back end / thick client background, so maybe I'm missing something... but I recently looked at the source for an open source JWT token server and the authors went crazy with await / async. Like on every method and every line.
I get what the pattern is for... to run long running tasks in a separate thread. In my thick client days, I would use it if a method might take a few seconds, so as not to block the GUI thread... but definitely not on a method that takes a few ms.
Is this excessive use of await / async something you need for web dev or for something like Angular? This was in a JWT token server, so not even seeing what it has to do with any of those. It's just a REST end point.
How is making every single line async going to improve performace? To me, it'll kill performance from spinning up all those threads, no?
I get what the pattern is for... to run long running tasks in a separate thread.
This is absolutely not what this pattern is for.
Await does not put the operation on a new thread. Make sure that is very clear to you. Await schedules the remaining work as the continuation of the high latency operation.
Await does not make a synchronous operation into an asynchronous concurrent operation. Await enables programmers who are working with a model that is already asynchronous to write their logic to resemble synchronous workflows. Await neither creates nor destroys asynchrony; it manages existing asynchrony.
Spinning up a new thread is like hiring a worker. When you await a task, you are not hiring a worker to do that task. You are asking "is this task already done? If not, call me back when its done so I can keep doing work that depends on that task. In the meanwhile, I'm going to go work on this other thing over here..."
If you're doing your taxes and you find you need a number from your work, and the mail hasn't arrived yet, you don't hire a worker to wait by the mailbox. You make a note of where you were in your taxes, go get other stuff done, and when the mail comes, you pick up where you left off. That's await. It's asynchronously waiting for a result.
Is this excessive use of await / async something you need for web dev or for something like Angular?
It's to manage latency.
How is making every single line async going to improve performance?
In two ways. First, by ensuring that applications remain responsive in a world with high-latency operations. That kind of performance is important to users who don't want their apps to hang. Second, by providing developers with tools for expressing the data dependency relationships in asynchronous workflows. By not blocking on high-latency operations, system resources are freed up to work on unblocked operations.
To me, it'll kill performance from spinning up all those threads, no?
There are no threads. Concurrency is a mechanism for achieving asynchrony; it is not the only one.
Ok, so if I write code like: await someMethod1(); await someMethod2(); await someMethod3(); that is magically going to make the app more responsive?
More responsive compared to what? Compared to calling those methods without awaiting them? No, of course not. Compared to synchronously waiting for the tasks to complete? Absolutely, yes.
That's what I'm not getting I guess. If you awaited on all 3 at the end, then yeah, you're running the 3 methods in parallel.
No no no. Stop thinking about parallelism. There need not be any parallelism.
Think about it this way. You wish to make a fried egg sandwich. You have the following tasks:
Three tasks. The third task depends on the results of the first two, but the first two tasks do not depend on each other. So, here are some workflows:
The problem is that you could be putting the toast in the toaster while the egg is cooking. Alternative workflow:
Do you see why the asynchronous workflow is far more efficient? You get lots of stuff done while you're waiting for the high latency operation to complete. But you did not hire an egg chef and a toast chef. There are no new threads!
The workflow I proposed would be:
eggtask = FryEggAsync(); toasttask = MakeToastAsync(); egg = await eggtask; toast = await toasttask; return MakeSandwich(egg, toast);
Now, compare that to:
eggtask = FryEggAsync(); egg = await eggtask; toasttask = MakeToastAsync(); toast = await toasttask; return MakeSandwich(egg, toast);
Do you see how that workflow differs? This workflow is:
This workflow is less efficient because we have failed to capture the fact that the toast and egg tasks are high latency and independent. But it is surely more efficient use of resources than doing nothing while you're waiting for the egg to cook.
The point of this whole thing is: threads are insanely expensive, so don't spin up new threads. Rather, make more efficient use of the thread you've got by putting it to work while you're doing high latency operations. Await is not about spinning up new threads; it is about getting more work done on one thread in a world with high latency computation.
Maybe that computation is being done on another thread, maybe it's blocked on disk, whatever. Doesn't matter. The point is, await is for managing that asynchrony, not creating it.