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…
Asynchronous Programming in C#
41–50 of 186 posts
Re: Asynchronous Programming in C#
#42Async/await was delivered after the popular .NET UI frameworks (WPF, UWP) were designed, and it shows.
Trying to work with data bindings with async is a pain. There are things WPF has to make it a bit easier, but UWP doesn't have them. A lot of the infrastructure (IValueConverter, for example) just won't allow async. There are workarounds, but they are ugly. It gets tricky when, as the document mentions, async is viral. Constructors and void methods (basically the only options for running initialization code when a UI component appears) give you not good options for async/await. A lot of the WinRT API (which has buggy C# bindings and is markedly unreliable) require async for things that were never async in the older implementations. It makes cross-platform library development a pain, and exacerbates the 'async is viral' issue.
None of what I mentioned is a 'problem' in that it can all be worked around and people have been delivering applications with such workarounds for a decade. But it is disappointing that Microsoft hasn't modernized the UI frameworks to take advantage of modern programming patterns.
Re: Asynchronous Programming in C#
#43Re: Asynchronous Programming in C#
#44http://joeduffyblog.com/2015/11/19/asynchronous-everything/ >We were able to share this experience with .NET in time for C#’s await to ship. Sadly, by then, .NET’s Task had already been made a class. Since .NET requires async method return types to be Tasks, they cannot be zero-allocation unless you go out of your way to use clumsy patterns like caching singleton Task objects.
.NET Core and later has ValueTask for that usecase.
Just lately I did some Entity Framework coding and noticed that some things are async compatible, but others aren't, so you end up doing a lot of strategizing coding around these omissions and creating questionable workarounds.
I really wish they would go back to the drawing board and simplify things. Same could be said for their various XAML dialects. It's just too damn verbose.
Re: Asynchronous Programming in C#
#45Re: Asynchronous Programming in C#
#46I 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…
Totally agree. At first look async/await is simple and straightforward but it's way to easy to mess up in subtle ways. Most people don't even notice that their code has problems until they get weird behavior in production.
In general I believe they made async way too pervasive in the framework and are also inconsistent.
Re: Asynchronous Programming in C#
#47Why do we need the `async` keyword? What is the difference between a function which returns a Task , and an async function which returns a Task ?
Re: Asynchronous Programming in C#
#48I 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…
Strongly agree. Honestly, just the first point "Asynchrony is viral" is a huge fucking flag that this implementation sucks. It doesn't need to be viral, they just needed to make passing a continuation easy , and they failed miserably. Overall - I really like most of C#, but that async/await implementation is poor at best.
Which means that .NET code tends to suffer from the same issue as Go code. The solution is the same as well: Separate out the code that does logic processing from the code that does I/O. This way only a few top level functions will become async. I find that this makes my code cleaner and more testable as well.
Re: Asynchronous Programming in C#
#49We 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…
This is correct, it's for increasing _throughput_ in concurrent scenarios. Meaning that when your server is processing multiple requests at the same time, yielding back rather than busy-waiting allows a different request to progress instead (or even to start processing a queued request earlier).
When waiting for I/O with another machine (a database, an API, etc) you can't wait faster; but you can wait better.
Re: Asynchronous Programming in C#
#50We 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…
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://stackoverflow.com/a/22862989/635314). However, I'm not sure how any of this relates to "go[ing] as fast as possible", since surely you would simply not use a Task.Delay in that case.
> There is a shitload of context switching and other barbarism that occurs when you employ async/await.
Async/await reduces context switching over the alternative of having one thread per request (i.e, many more OS threads than cores) and it (async/await) exhibits the same amount of context switching as Goroutines in Go and other M:N schedulers. If there is work enqueued to be processed on the thread pool, then that work will be processed without yielding back to the OS. The .NET Thread Pool dynamically sizes itself depending on the workload in an attempt to maximize throughput. If your code is not blocking threads during IO, you would ideally end up with 1 thread per core (you can configure that if you want).
Async/await can introduce overhead, though, so if you're writing very high-performance systems, then you may want to consider when to use it versus when to use other approaches as well as the relevant optimizations which can be implemented. 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.