Live data from Hacker News

Asynchronous Programming in C#

github.com

91–100 of 186 posts

Re: Asynchronous Programming in C#

#91

I would call myself an extremely experienced and knowledgable C# programmer with 10+ years of experience and even I found a few things surprising or new in this guide. I think C# async/await implementation is the biggest con on the .NET community, because it gets constantly hailed as one of the easiest ways of async programming but this guide itself proves to me that there are so many gotchas which are not obvious at…

The way I put it: .NET async makes the easy things easier and the hard things harder. The problem is that Task/Task was the foundation for async, and it's a bad foundation. Even with the ability to write your own duck-typed awaiters (and the advent of ValueTask), the widespread use of Task means if you're writing async code you're going to have a tough time getting away from it.

I think this is the crux of the matter. Since Task and the TPL predated async, iirc, people get befuddled by the parallelism Vs concurrency (if that's the correct term) parts of the Task API.

Certainly the async story is a lot more complicated in desktop but it is very simple for most server scenarios, simply put "use this async call so that the thread can do other things while you wait for the db to respond" and the model in code is much preferable to callback hell.

Re: Asynchronous Programming in C#

#92

Is there a rule as to which methods are best made async and which not? Or, once you start using async would it be best to make ALL methods async? Many methods could be either sync or async. But if you make a method that doesn't strictly need to be async async you give yourself the option of later making it actually return its result after a delay, say reading its answer from the web or asynchronously from disk. Where…

Another downside is the overhead created. Those “simple” async methods are translated into state machine classes under the hood. You could probably test performance and see if the value you get is worth it.

Re: Asynchronous Programming in C#

#93

The sync over async issue is a real common problem for me when trying to get a large older codebase converted to async and you can't just do it all at once. You still need support non async callers and you want to share code between the new async version and the old sync versions it makes it really difficult to do so. Say you have a db layer you want to move to async but you still have to support a sync api over that…

Database operations should be async, you shouldn't consume them synchronously, as they do IO. Async/Await came out in 2012, almost a decade ago (and with great first party library support, I might add). Moralizing aside, sometimes you do want to call async APIs as synchronous code. I don't think there should be a synchronous version of the API implemented as well, you just need to do var myValue = DoSomethingAsync().…

>> var myValue = DoSomethingAsync().ConfigureAwait(false).Result;

Doing this inside ASP.NET request processing code (e.g. a controller method) will result in thread pool starvation [1], if you see about 50-100 (the numbers are off the top of my head, so check for yourself) requests per minute hitting that line of code.

P.S.: Sorry for a medium link, but couldn't really find an alternative.

[1]: https://medium.com/criteo-engineering/net-threadpool-starvat...

Re: Asynchronous Programming in C#

#94
post #84

I used C#'s async/await on a project in 2017, and I took to it. I appreciated being able to follow the "relevant" parts of a method, without having to jump around to different callbacks. That being said, I think I was the only one on the project that understood it _well_. Over the course of two years, I learned lots of the same gotchas. Avoid "async void" was one of the catchy mnemonics I learned the hard way, becaus…

You won't need to rewrite into async model, because project Loom will introduce virtual threads. That means your sync code will look exactly the same, but will have scalability of async.

Re: Asynchronous Programming in C#

#95
post #6

We use async/await pretty much universally throughout our codebase today. One thing to keep in mind is that this mode of programming is actually not the most performant way to handle many problems. It is simply the most expedient way to manage I/O and spread trivial things across many cores in large, complex codebases. You can typically retrofit an existing code pile to be async-capable without a whole lot of sufferi…

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.

Yes it is. Async is avoid blocking operations, whether it's IO-bound or CPU-bound. There are plenty of cases where computation can be offloaded to async tasks (eg: keeping the UI responsive).

The official docs even give examples to clarify both scenarios: https://docs.microsoft.com/en-us/dotnet/csharp/async

Re: Asynchronous Programming in C#

#96
post #6

We use async/await pretty much universally throughout our codebase today. One thing to keep in mind is that this mode of programming is actually not the most performant way to handle many problems. It is simply the most expedient way to manage I/O and spread trivial things across many cores in large, complex codebases. You can typically retrofit an existing code pile to be async-capable without a whole lot of sufferi…

> Consider that the minimum grain of a Task.Delay is 1 millisecond. The minimum here is contingent on a few things. The API can accept a TimeSpan which can express durations as low as 100ns (10M ticks per second: https://docs.microsoft.com/dotnet/api/system.timespan.ticksp... ). The actual delay is subject to the timer frequency, which can be as high as 16ms and depends on the OS configuration (eg, see https://stacko…

> I'd recommend people take the simple approach of using async/await at the application layer and only change that approach if profiling demonstrates that it's becoming a performance bottleneck.

Despite some of the things I presented in my original comment, I absolutely agree with this. There are only a few extreme cases where async/await simply can't get the job done. These edge cases are usually explicitly discovered up front. It's rare to accidentally stumble into one of these ultra-low-latency problem spaces in most practical business applications.

Re: Asynchronous Programming in C#

#97
post #6

We use async/await pretty much universally throughout our codebase today. One thing to keep in mind is that this mode of programming is actually not the most performant way to handle many problems. It is simply the most expedient way to manage I/O and spread trivial things across many cores in large, complex codebases. You can typically retrofit an existing code pile to be async-capable without a whole lot of sufferi…

> and spread trivial things across many cores in large, complex codebases How are tasks spread across cores? My main experience with the "await" paradigm is from Python, which is primarily single threaded.

The .NET runtime has a threadpool with local/software threads that share the workload. The Tasks (from async operations) are spread across this threadpool, although depending on many factors (how quick it finishes, overall load, etc) they might just run on the same thread anyway.

Re: Asynchronous Programming in C#

#98
post #57
post #14

C# 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…

It's kind of odd that JetBrains chose async/await for Kotlin considering the JVM is going towards the Go approach for virtual threads. I guess they had to since they wanted to support android/js?

The decision happened before Loom came to be.

It is yet another example of impedance mismatch from guest languages, when the platform moves into another direction.

The platform language gets the true way, while the guest languages get the hard decision how to combine multiple approaches, and libraries that only use the new platform APIs.

Re: Asynchronous Programming in C#

#99

Earlier quoted context omitted.

Around 50% of my work .NET coding and I find It's becoming really hard to keep up with this. .NET more and more feels to me like the typical MS approach where they just keep cranking out new stuff without cleaning up existing stuff. Some of the new things are very good, some are half baked, and it's difficult to figure out on what side these new features are. Just lately I did some Entity Framework coding and noticed…

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#

#100

Earlier quoted context omitted.

Database operations should be async, you shouldn't consume them synchronously, as they do IO. Async/Await came out in 2012, almost a decade ago (and with great first party library support, I might add). Moralizing aside, sometimes you do want to call async APIs as synchronous code. I don't think there should be a synchronous version of the API implemented as well, you just need to do var myValue = DoSomethingAsync().…

Some things simply don't have an async API at the low level, e.g. DNS lookup: there is no asynchronous version of getaddrinfo(3). So if you look at the .NET sources, you'll see that Dns.GetHostEntryAsync pushes a task to a thread pool that calls getaddrinfo(3). In the end, you arrive at a "sync top-level APIs -- async library APIs -- sync low-level OS APIs" sandwich of dubious efficiency.

[deleted]
Post reply on HN