What's the right way to do throttled async in modern C#? For some context, we have a process that needs to make an API call for each row in a file - maybe hundreds or thousands. What's the best way beyond Wait()'ing for each one to get decent performance without DOS'ing the server?
Asynchronous Programming in C#
121–130 of 186 posts
Re: Asynchronous Programming in C#
#122C# was my first exposure to async/await back in 2015 and I initially had trouble wrapping my head around various details (i.e. ConfigureAwait etc.). I think the languages that have done best job in removing all that detail are Go and Elixir (Beam based languages). Which if you pay attention removed the overhead of rewiring your brain to do async/await all the way down. I repeated async/await systems recently with Kot…
There are some other choices they made that are arguably not the right ones - for example, async code can do some of its initial execution on the calling thread and do the rest wherever continuations get scheduled (which is configurable...) which means you have to have exception handling in two places and the way the exception handling works will be different (the article calls this out). It is possible to avoid this by having the initial call to the async function only create the task but not run any of it - of course, there are reasons not to do it, performance being one of them, so it makes sense that they did it... it's just bad to optimize by default instead of making code simpler and more reliable.
My least favorite decision is that inexplicably, async/await state machines are very error prone... if any part of your codebase accidentally invokes a continuation twice, the state machine will potentially begin running twice or even start running again from the beginning with the same local variables. Fixing this would have been as simple as setting a bool at the end and checking it at the beginning, but for some reason they are dead-set on not fixing it. Premature optimization once again.
The existence of 'async void' is also just a complete trainwreck. They shouldn't have allowed it, especially since an 'async Task' that discards its result is just as easy.
The approach to cancellation (intrusive only) is also needlessly complex and gross. Putting a Dispose method on a Task would allow consumers of any async API to cleanly signal that they no longer need the result of a Task and any implementation would be able to observe this without anyone having to introduce a new method overload that takes a CancellationToken, not to mention that the intrusive cancellation design creates extra garbage on the heap. Really not obvious to me why they did this instead of reusing 'using x' and IDisposable.
Re: Asynchronous Programming in C#
#123Earlier quoted context omitted.
As someone who has never really used promises or futures, what do they add, or how do they make concurrent programming easier or clearer than what's currently in Go?
In short, they provide clean API for checking on completion and error states of a long-running process from another thread without blocking that thread. This is an essential pattern for UI-related tasks, including web pages.
Re: Asynchronous Programming in C#
#124Earlier quoted context omitted.
async/await is not for CPU-intensive parallelism. I think that's pretty much stated in the .NET docs. That's why Parallel Compute APIs like Parallel.ForEeach/For are not async. Their purpose is to enable non-blocking waits for IO, as well as to do stuff like animation on UI where you might want to execute procedural code over a larger timeframe.
The other reason those Parallel methods did use async/await is that async/await did not exist in .NET at the time those methods were introduced. But good news! The upcoming .NET 6 release will have a Parallel.ForEachAsync method: https://docs.microsoft.com/dotnet/api/system.threading.tasks...
Re: Asynchronous Programming in C#
#125Earlier quoted context omitted.
The other reason those Parallel methods did use async/await is that async/await did not exist in .NET at the time those methods were introduced. But good news! The upcoming .NET 6 release will have a Parallel.ForEachAsync method: https://docs.microsoft.com/dotnet/api/system.threading.tasks...
Doing a bit of .NET archeology we find that both Task and Parallel.For can be dated to .NET 4.0 So if they wanted to, they could've included async/await support. It just didn't make sense.
I think it was possible to have async/await in .net framework 4.0 via some workarounds when it was still in CTP mode but I don't recall the details.
Re: Asynchronous Programming in C#
#126Earlier quoted context omitted.
In short, they provide clean API for checking on completion and error states of a long-running process from another thread without blocking that thread. This is an essential pattern for UI-related tasks, including web pages.
This is built into the .NET API though? You can just check the Faulted and Completed properties of the Task you're holding.
Re: Asynchronous Programming in C#
#127Earlier quoted context omitted.
The problem is that .NET has been taken over by web developers, and they expect the kind of breakneck pace of change and half-baked tools that the Javascript ecosystem has become accustomed to.
This is so true. .NET has been steadily going downhill for some time now. The best indicator is the absolutely rotten documentation for the more recent .NET stuff. Compare that to the older .NET Framework and/or Winapi documentation which was excellent.
Re: Asynchronous Programming in C#
#128Earlier quoted context omitted.
"var myValue = DoSomethingAsync().ConfigureAwait(false).Result;" In my view there should be a built-in keyword to do this right. It's too easy to get this wrong and even worse possible problems only show up rarely.
The reason there isn't a keyword is because its not possible to do it right. The example given is far from foolproof.
Re: Asynchronous Programming in C#
#129Earlier quoted context omitted.
It is fighting in a space which is very competitive. Java, Go, JavaScript and Python. The later two are being favorite of every university or coding camp graduate. You stay relevant or you die. Unfortunately, that implies faster dev cycles and areas like docs which are not well served.
How is .NET fighting against JavaScript or Python? Java or Go, I can understand but not JavaScript or Python.
Re: Asynchronous Programming in C#
#130>Prefer async/await over directly returning Task This one seems questionable to me. I've never been bitten by any of the cons mentioned[1], and it's even noted that doing it this way does incur performance costs. I've learned over the years that if the code path is very prolific, it pays to avoid the async state machine. I'm curious if others could expand on this one. [1] https://github.com/davidfowl/AspNetCoreDiagno…
Unless you're doing awaits in a tight loop of thousands/millions of calls, the overhead of the state machine is almost non-existent, which leads to the next question, what are you doing that requires await in a tight loop of that many calls? The whole point of await is to use it to yield a thread while waiting on a long running operation, if your await returns nearly instantly then use the synchronous version and avo…
It's possible to work around this efficiently by pulling the async code into a separate method and using ValueTask for the outer method return type.