5 ms·
> Asynchrony is viral > 1) Once you go async, all of your callers SHOULD be async, since efforts to be async amount to nothing unless the entire call stack is
by mrkeen 3y ago
> Asynchrony is viral
> 1) Once you go async, all of your callers SHOULD be async, since efforts to be async amount to nothing unless the entire call stack is async.
> 2) In many cases, being partially asynchronous can be worse than being entirely synchronous.
> 3) Therefore it is best to go all in, and make everything async at once.
I agree that all callers should become async. But I disagree that all callees should also be async, which is what 2 and 3 seem to imply.
You don't async for async's sake; you async to route around delays caused by blocking calls.
In their good example,
public async Task<int> DoSomethingAsync()
{
var result = await CallDependencyAsync();
return result + 1;
}
they've included a line of business logic after the async machinery. If this logic grew to more than just (result + 1), I'd expect that code to be in a separate synchronous function.
I probably also wouldn't write out DoSomethingAsync() in full, either in the simple example above, or in a version with more complicated result-handling. Most of it is boilerplate:
start a function
call one function
un-async the result into one variable
do one thing to that variable
repack it as async
return it
If you want 'one bigger than CallDependencyAsync()', why not:
CallDependencyAsync().ContinueWith(r => r + 1)
and if the logic grows, then:
CallDependencyAsync().ContinueWith(r => handle(r))
private int handle(int result) {..}
- Salgat 3y agoThey're referring to not using .Wait()/.Result on awaitable functions, not about making every function async regardless of whether it needs it. This was a common pitfall that people would do back in the day to avoid having to refactor everything when adding async support to the code, since one await deep in the code could cause half your functions to need async added in a refractor.
- mrkeen 3y ago> not about making every function async regardless of whether it needs it. That's what you and I wrote. That's not what the article wrote. "efforts to be async amount to nothing unless the entire call stack is async" The entire call stack? "it is best to go all in, and make everything async at once." Go all in? This beyond 'a little bit unclear' into 'incorrect' territory, especially since the preceding paragraph said "there's been lots of confusion on the best practices for async and how to use it properly." Is there a single NB or asterisk-like comment on the whole page that walks back the "all in" comment to something like "calling sync from async is fine." ?
- Salgat 3y agoHe explains the same thing I did right in his example. Don't use .Result to force sync over async.
- mrkeen 3y agoHe says not to blocking-wait for async methods, which is correct. He makes no direct comment, afaik, on calling sync methods from async methods. The reader is left only with efforts to be async amount to nothing unless the entire call stack is async and it is best to go all in, and make everything async at once. and must somehow parse this as some of the call stack, and make some things async.
- davidfowl 3y agoIf I made mistakes feel free to file an issue or even send me a PR. It's open source! That said, you're right that I don't say how best to call sync from async methods (the latter is more difficult as there's no good way do it well).
- Hawxy 3y ago> why not Because ContinueWith is considered antiquated in modern C# and shouldn't be used for a multitude of reasons? https://medium.com/@joni2nja/why-you-should-not-use-continuewith-in-your-async-code-c9eaf6087e64 https://medium.com/@joni2nja/why-you-should-not-use-continue...
- mrkeen 3y agoSo does C# not have map yet? (I figured `ContinueWith` was just dumb naming to avoid 'map' at all costs, just like how Java went with `thenApply`.)
- Hawxy 3y agoSure, you can use it like that, but it's not considered good practice. I think the context missing here is that most modern C# applications are going to be async all of the way down. The entry point can be async. Background service abstractions are async. Your API endpoints in ASP.NET Core are typically async as you're going to be calling some async I/O anyways (database queries, HTTP clients). There's no benefit to writing something in the old callback model when the rest of your code is async/await anyways.
- pjc50 3y ago> So does C# not have map yet? Have you heard the word of our lord and savior, LINQ?