Stop using async void in C#! Do this instead.
HTML-код
- Опубликовано: 1 мар 2023
- Use code REST15 for 15% off the new From Zero to Hero - REST APIs in .NET course: bit.ly/restchapsas
Become a Patreon and get source code access: / nickchapsas
Hello everybody I'm Nick and in this video I will show you why you should not be using async void in C#. It is a very common mistake that can have very catastrophic effects for your application and in this video I will explain why.
Blog by Gérald Barré: www.meziantou.net/fire-and-fo...
Workshops: bit.ly/nickworkshops
Don't forget to comment, like and subscribe :)
Social Media:
Follow me on GitHub: bit.ly/ChapsasGitHub
Follow me on Twitter: bit.ly/ChapsasTwitter
Connect on LinkedIn: bit.ly/ChapsasLinkedIn
Keep coding merch: keepcoding.shop
#csharp #dotnet
Would definitely like to see how to properly code for long running tasks, please! You are awesome and I sincerely appreciate your videos! Thank you for your time. Edit: No, I didn't know all the caveats, thank you for explaining the issue and describing why and how it all works.
I learned about Task and exceptions the hard way. This video explains it really well! I'd love to get some info on long running tasks, as that is something I deal with at work every day.
Thanks, Nick!
Having more info about long running tasks would be great. I often heard that you shouldn't create long running background tasks but never found a clear explanation why.
AFAIK thread pool is designed for exactly what the name stands for - the thread should do work fast and go back to the pool when it's done in order to get next item on "to do list". What you are doing with a long running task is you're stealing the thread from thread pool indefinitely. The thread is not really pooled anymore, right? It's better to start a dedicated thread that is not rented from the pool in the first place. Also you don't have control over thread pool threads e.g. should it be foreground or background etc.
I'm always up for more videos on async stuff, since it's one of the most unintuitive areas in C#.
On an unrelated note, I would also love to see some videos about unsafe coding. When it's needed or not, the pitfalls to lookout for and common practices to follow.
Good video! And yes, long running background tasks please 🙏
I really love videos on C# asynchronous programming model, it's so elegant the Task-Based approach🤘😍
Yeah, video about long running Tasks would be helpful!
Thank you for collecting this info in one place. This is exactly what I was curious about. Great info. I'd love that long running tasks video!
6:00 - good point about Func and Action
Internally we create an extension method to tasks that requires an Action and optional Action for continuing with. Saw this from Brian Lagunas video on RUclips years back.
Yes please Nick, would really like to learn more about long running background tasks. Especially with regards to desktop\WPF\WinForms
For one of the projects I work on I created a custom thread pool for tasks, since one executable handles multiple services. I created a FireAndForget method on it to deal with this specifically. I also added a function for long running tasks, which would create a named thread for the task to run on, so you can find it in the threads list easily.
Hi Nick, Thank you for the great video and explanations.
I would be very interested in a long background runner tasks video :)
Me too. In my project I have some long (permanently) running threads, which do some job, stores it in a dictionary, which the main thread uses (consumes) in intervals. I think there is some way to create it via tasks, but I think doing it via threads is more suitable. I remember using some enum which set it to a long running task.
Is it true that one should preferably use tasks instead of threads directly?
Thank you Nick! Yes, more async vids!
The Action silent void is definitely a gotcha to keep a lookout for
As for extremely long running tasks however, I definitely recommend utilizing the PUB/SUB message queue methodologies. The subscriber model is truly a "fire and forget" and will completely release your threads.
Thanks for another great video.
Hi Nick,
Very nice video. Am more interested on long running backgroundTask video
Hi Nick! Great content as always!
yayy new nick upload!
Very interesting, especially since we are forced by the class library to use async void in some places, it's great to know the gotchas. I hadn't realised how dangerous unhandled exceptions could be inside an async void function.
For fire & forget I'd typically just receive the Task but not await it ( _ = DoThing() ), or use a message queue and handle it elsewhere, depending on what the task actually is.
Yes, a video about long running threads would be great. I frequently use a thread to monitor external hardware and am still using the old Thread.Start() API, with a worker loop that does the hardware monitoring logic and a frequent Thread.Sleep(). This usually runs for the life of the application, and it works well, managing a job queue for the hardware, re-establishing connections, raising event etc. and is a very mature pattern for us. but I'm sure that in the new async world there's a more modern design pattern that I should be considering.
Very interesting video as always.
I'm interested too with long background runner taskas
I would definitely like to see the long-running task version!
The thing I do for fire and forget is just have a small helper method (called FireNForget) that takes a Func (func so it can capture both sync and async exceptions), and wraps everything in a try-catch(Exception ex), with the catch block (carefully!) logging the exception where it can be noted. FireNForget is very deliberately made short and simple enough that as little as possible is done outside the try-catch guard, and hasn't failed me. Does this seem like a good solution? Does it seem like there are any problems with this?
Great content as always.
There are so many nuances with Tasks to be mindful of. I already figured out exceptions not being caught in calling thread, but good to know about those solutions.
Thanks for this informative video Nick! Question, what do you consider short running and long running? Is > 3 seconds long and < 3 seconds short?
Nick we need a video on long running background tasks - preferably in the realm of http requests etc
nick:
your code could be in danger.
my code:
I'm not in danger, I am the danger skyler.
i would love to see more about async programming in c# :)
Definitely want a video on long running background tasks
Definitely make a video on longer running tasks 👍
I'd love to see a video on long running tasks, also. When one makes a threading mistake, it can be impossible to recreate or debug.
The one thing I always do in a long running compute intensive task is to make sure it is going to yield periodically. Adding a periodic short Sleep() can make a process that's running 100% CPU become 'idle', since the processing is broken into such small timeframes interspersed with the Sleep.
Great video! Saved me a headache, I'm coming from async/await in JS and then async/await in Python, now using this paradigm in C# and of course there's all these subtle differences in every language 🙄
Since you mentioned it, I really would like a video on long running background tasks.
I am rather worried about my use of QueueBackgroundWorkItem being a very improper way of doing it in IIS, and that IRegisteredObject with its own thread isn't quite right either.
Except for maybe a file watcher, I can't really think of any client side uses for such...
Thanks for reminding ForEach with Action of T.
Would love to see how you handle Long running tasks. Thanks
Great video, please do long running
I would love to hear your take on long running tasks. I've run into this multiple times in my career where we wanted to trigger a long running event off of an API Endpoint, and the controller eventually decides it's done with the fire and forget task and the task just stops.
Hi Nick, thank you for this video. What is the behavior when using the discard '_ =' instead 'await' in these scenarios?
Yes, please made a video on Long running operations!
@nick Do you think you could include how to handle AggregateExceptions in this same context? My try catch outside of a function that threw an aggregate exception never returned and crashed my program
You could also use the ContinueWith method on the task and see if the thread is faulted then handle the exception?? However you would need to do it for every call to the asyn method 😔.
Great video, thanks Nick 👍
I almost didn't click on this one because I expected yet another (pedantic) rant on how async void hides the function from the exception stack trace and whatnot as seemingly everyone that talks about c# has done before. But this is actually highlighting a small but helpful and important detail that I didn't know about.
You can override async void in your code base to route exceptions to a logger instead of crashing the app. See the blog post "Extending the async methods in C#" by Sergey Tepliakov from 2018.
Unfortunately, C# 10 async overrides don't support async void, so that's the only way to override it (will apply to the entire assembly).
Long running background tasks… yes, interested!
Would be great to have a video on long running background tasks which can run in parallel and start manually from different controllers
Hi, in fact I didn't know about async void, always used async Task. Thanks.
Do you plan to make zero to hero about all there is to know about threads? Threads, Tasks in general are very useful but can be tricky.
Hi, Nick. Can you make course about grpc in dotnet?
I have often wondered how to safely handle longer running operations in a separate thread from a button event in a WinForms app. I would appreciate some advice on that. I typically mark the OnClick event as async, create a class for the long runner, new up the class and call the async method with an await and try catch in my OnClick. This video makes me think that my approach is way wrong.
What'd be an alternative when working with Windows Forms?
it really does my head in all these different ways that async methods deal with exceptions.
I am working on a worker service that will on background and will scrape data continuously, and ofcourse the service will be running for long periods. Does worker service handles this case automatically?
CC: "hello everybody I'm naked in this video"
Well, that was a lie. :(
I'd like to see the long running task video as well
Please do a video on long-running background tasks!
Can u make a tutorial/video about „exception handling best practices“?
Hi Nick! Thanks for the valuable videos :) After watching your video a question came to my mind ... I am wondering if it would be wise to do so: Task.Run(async () => await someAsyncMethod()).ContinueWith((task) => { ... }).Forget();
Long running task (i consider long anything over a second) thats need to wait for results and perform in the background would be great to see your take on it.
Task.Factory.StartNew(..., ...LongRunning)
@@diadetediotedio6918 I know this is wotking and TaskCreationOptions.LongRunning need also to be considered bit i want nick take on that. I tried to suggest this before in the clean consumer video he made but i guess i wasnt clear enough about my question
I really want to learn more about long running tasks, I've tried using them with a consumer system, but I ran into issues of objects not getting out of scope of my while loop and GC not collecting things ending up in a memory leak.
I would love a vid about long running tasks too please.
I'm working on a little robot that has a cam attacked and is supposed to constanly fetch and process the frames that come in via OpenCV.
Currently I'm running the logic inside a Task.Run() but I guess that's not a good approach...
Hi, it will be pretty cool if you`ll make video about concurrent collections.
There not so many videos about them on yt
I agree with others... I would like to see a video on long-running background tasks
I would like to see a video about long running tasks
What is the difference between
bgTask.RunAsync()
and
Task.Run(async => await bgTask.RunAsync())
?
I'm wondering how Windows forms require button click events to return void, even when they are async.
yes pleeease, 2 things i really need to understand:
1. long running background tasks.
2. .ConfigureAwait(false)
I stopped using async void ever since your first video warning about it's potential dangers
I am using async void on a Blazor WebAssembly app. I am updating the UI every 5 seconds, so to configure the periodic timer I use async void inside the OnInitializedAsync event without awaiting it. Are there better ways to use background long running tasks on blazor wasm?
In MAUI I use MainThread.InvokeOnMainThreasAsync
Use PeriodicTimer, you can do
while(await timer.WaitNextTickAsync())
await callback()
Or something like this?
@@ghevisartor6005 I am doing this but to make the loop run in background I wrap that logic on a async void method
@@keke772 also i dont know really about webassembly but you have to InvokeAsync in Blazor server if you update the Ui from another thread ofc.
Oh learned this the hard way. In production xD
Usually in Task.Run(t => task). I would like to see long running task video.
Another request for covering long running tasks
Please make the video about long running tasks. I have done this a thousend time and there dont seem to be any way which didnt cause problems at the one or antoher point... 🙈
So in Blazor there is the EventCallback where you can only give an void-Method in. How should you avoid async void there? Is there any possibility? Just using void and start an task or what?
What do you mean you can only give a void method in? You mean the function you set on the component from outside, that get executed when the event callback is invoked?
You can put an async Task method and it works, not just void.
@@ghevisartor6005 Oh... Damn I don't know why I had problems with it... You are absolutely right, I tried it. Sorry ;-)
@@Yannici no problem sometimes it's even the compiler giving false errors
I have never used asynch void. I have never even thought of using this.
I had attempted to use an async void before, needless to say, it blew up in my face but didn't crash the app.
Learned my lesson the hard way to always use at least an untyped `async Task`...
Do a Video on long running background
is there any cons in using async void if we were to put try catch in it? any performance impact or whatsoever?
the cost of catching exception in dotnet is told to be not so cheap. Sometimes, it will go easily over a millisecond and may impact on UI thread's refreshing the display.
Along with async void, awaiting a task is conduit thru which the exception flows to the principal thread.
What really matters is not letting worker thread's exception thrown to calling thread. If you make it sure, it doesn't matter you use either of async void or async Task.
Just trying consumes almost nothing, but the catching part is actually the problem
The method knows what it is doing, but not why this is done. This might prevent meaningful handling of the exception.
i can not buy your courses because i have 4 digits pin on the card, but it allows only 3 to enter ) something wrong ) @nick
Long-running background task!!
Would global error handler prevent from application crash?
Why don't WPF have async Task Button1_Click handler instead? I think it's obvious to have this overload to avoid app crash... Anyway it's a very common scenario when you pass async task in the non-async functions, like Parallel.For/ForEach and it's transformed to async void
Probably because WPF is utter trash and always has been.
1. WFP and WinForms have their own synchronization context so it works a bit differently since it doesn't just put the exception on a random thread from the threadpool.
2. It doesn't really matter since the framework doesn't handle the exceptions in any meaningful way anyway so it'd just crash regardless.
Thanks, now i know that i did some bugs 🙂
What about '_ = bgTask().ContinueWith((t) => { if (t.IsFaulted) { // here we have t.Exception of type AggregateException, having all exceptions occured in background } });
Rolls off the tongue
I also like it better. Task.Run() is pretty overused imho
What do you do when you have no other choice (like in unity?)
I explained that in the WPF section
Good content. A remark for improvement: Speak slowly, it will help and improve the message delivery.
while I would be interested in how to fire and forget long running tasks, I'd be even more interested in examples where this would be useful. my gut feeling tells me that if you use long-running fire and forget tasks, your design is probably wrong. just a gut feeling, though, so I'd like to have that thought challenged 🤓
I still don't understand. why not just try catch in all your async tasks? Edit: To answer my own question, I looked at the forget extension and that's pretty much what it does. Wrap the call in a try catch block and discard resuming on the original synchronization context. A convoluted video a rudimentary solution.
Long running tasks!!
FireAndForget == Thread.
From my point of view.
At least for long-running tasks
of cource you MUST using try-catch where possible something can goes wrong! its a base
I'm appalled the compiler even allows async void. I would never write something like that intentionally.
What about using a discard? `_ = SomeTask();` for example.
That doesn't prevent UnobservedTaskException, that just tells the C# analyzer to stop warning you about it.
@@pierwszywolnynick Suppressing the warning doesn't prevent the crash.
[Edit] Sorry, UnobservedTaskException used to crash the process, but they changed the behavior in .Net 4.5.
This behaviour is seen in many languages 🙂
Asynchronous things are always complicated.
Wait, list.ForEach is a thing?...
//crash
catch (Exception ex)
{
Console.WriteLine(ex);
}
//Don`t crash
catch (Exception ex)
{
Console.WriteLine(ex.Message);
//don`t crash and show a message
}
or
catch (Exception ex)
{
Debug.Print(ex.Message);
}
Ahh Tasks, thank God for Stephen Cleary many years ago.
C#'s asynchronous-y has so many confusing ifs that makes it bad
When i saw this video i said that Stephen toub is coming 😂
sometimes async void is good
You could just pass a waithandle to it and wait for it to finish…