Stop using async void in C#! Do this instead.

Sdílet
Vložit
  • čas přidán 1. 03. 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

Komentáře • 154

  • @DeadDad1
    @DeadDad1 Před rokem +240

    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.

    • @Thial92
      @Thial92 Před rokem +7

      If you mean not waiting for a result then you can just create a service with a queue and just queue your tasks there. The service will loop over the queue and execute the tasks in the background while the Add/Queue method immediately returns allowing you to not wait.

    • @stefan-d.grigorescu
      @stefan-d.grigorescu Před rokem +2

      Also I think you could make the thread scheduling preemptive so that the queued task does not block a process forever

    • @jacobatchley8132
      @jacobatchley8132 Před rokem +2

      our organization had the need for distributed durable jobs; however, we didn't want. to be constraint to a cloud provider service.
      so we rolled our own solution and open sourced it.
      it uses mongo db to track job state and status and azure service bus.
      but those could be rotated out for any other infrastructure
      github/firebend/jobba
      you could also use something like hang fire or coravel

    • @yoel.taylor
      @yoel.taylor Před rokem +1

      For this you'd use a BackgroundService / Create your own IHostedService

    • @Thial92
      @Thial92 Před rokem

      @First Last You might want to look into things like Azure Service Bus.

  • @TheSilent333
    @TheSilent333 Před rokem +48

    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!

  • @Blu3Souls
    @Blu3Souls Před rokem +36

    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.

    • @hasmich
      @hasmich Před rokem

      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.

  • @WagnerGFX
    @WagnerGFX Před rokem +15

    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.

  • @mihankolt
    @mihankolt Před rokem +5

    Yeah, video about long running Tasks would be helpful!

  • @ivandrofly
    @ivandrofly Před rokem

    6:00 - good point about Func and Action

  • @SG_01
    @SG_01 Před rokem

    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.

  • @Kevmoens
    @Kevmoens Před rokem

    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 CZcams years back.

  • @chrismantonuk
    @chrismantonuk Před rokem +1

    Yes please Nick, would really like to learn more about long running background tasks. Especially with regards to desktop\WPF\WinForms

  • @islandparadise
    @islandparadise Před rokem +3

    Good video! And yes, long running background tasks please 🙏

  • @pablocom
    @pablocom Před rokem +4

    I really love videos on C# asynchronous programming model, it's so elegant the Task-Based approach🤘😍

  • @DavidSikesII
    @DavidSikesII Před 5 měsíci

    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!

  • @orterves
    @orterves Před rokem +1

    The Action silent void is definitely a gotcha to keep a lookout for

  • @klocugh12
    @klocugh12 Před rokem

    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.

  • @TampaCEO
    @TampaCEO Před rokem

    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.

  • @GlassScissors
    @GlassScissors Před rokem +4

    Hi Nick, Thank you for the great video and explanations.
    I would be very interested in a long background runner tasks video :)

    • @brianviktor8212
      @brianviktor8212 Před rokem +1

      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?

  • @ksdvishnukumar
    @ksdvishnukumar Před rokem +4

    Hi Nick,
    Very nice video. Am more interested on long running backgroundTask video

  • @ARESCOM_PA
    @ARESCOM_PA Před 6 měsíci

    Thanks for this informative video Nick! Question, what do you consider short running and long running? Is > 3 seconds long and < 3 seconds short?

  • @margosdesarian
    @margosdesarian Před rokem +3

    Nick we need a video on long running background tasks - preferably in the realm of http requests etc

  • @zeroaviation
    @zeroaviation Před rokem +2

    Thank you Nick! Yes, more async vids!

  • @LozrusX
    @LozrusX Před rokem +1

    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.

  • @nexor87
    @nexor87 Před rokem

    Very interesting video as always.
    I'm interested too with long background runner taskas

  • @alexanderkvenvolden4067
    @alexanderkvenvolden4067 Před rokem +5

    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?

  • @niklashjelm5959
    @niklashjelm5959 Před rokem

    Hi Nick! Great content as always!

  • @afouadr
    @afouadr Před rokem

    Thanks for reminding ForEach with Action of T.

  • @haroldorusso7878
    @haroldorusso7878 Před 7 měsíci

    Hi Nick, thank you for this video. What is the behavior when using the discard '_ =' instead 'await' in these scenarios?

  • @TheGamerHad
    @TheGamerHad Před rokem

    @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

  • @rajeshwaranpj3080
    @rajeshwaranpj3080 Před rokem

    Definitely want a video on long running background tasks

  • @KingOfBlades27
    @KingOfBlades27 Před rokem

    Definitely make a video on longer running tasks 👍

  • @Rose-ec6he
    @Rose-ec6he Před rokem +3

    yayy new nick upload!

  • @carndt124
    @carndt124 Před rokem

    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.

  • @SchnitzelMS
    @SchnitzelMS Před rokem

    i would love to see more about async programming in c# :)

  • @lexer_
    @lexer_ Před rokem

    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.

  • @MrTyler870
    @MrTyler870 Před rokem

    Great content as always.

  • @shkelqimhaxha3985
    @shkelqimhaxha3985 Před rokem

    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?

  • @rafaelg0225
    @rafaelg0225 Před rokem

    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 👍

  • @mattc4153
    @mattc4153 Před rokem

    Would love to see how you handle Long running tasks. Thanks

  • @ofiruzan6475
    @ofiruzan6475 Před rokem

    Would be great to have a video on long running background tasks which can run in parallel and start manually from different controllers

  • @peterrauscher
    @peterrauscher Před 3 měsíci

    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 🙄

  • @GioacchinoPiazzolla
    @GioacchinoPiazzolla Před rokem

    Yes, please made a video on Long running operations!

  • @Rose-ec6he
    @Rose-ec6he Před rokem

    it really does my head in all these different ways that async methods deal with exceptions.

  • @billy65bob
    @billy65bob Před rokem +2

    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...

  • @igorhenriques931
    @igorhenriques931 Před rokem

    What'd be an alternative when working with Windows Forms?

  • @ali_randomNumberHere
    @ali_randomNumberHere Před rokem +1

    nick:
    your code could be in danger.
    my code:
    I'm not in danger, I am the danger skyler.

  • @AkeemJonesajonesrock
    @AkeemJonesajonesrock Před rokem

    Great video, please do long running

  • @protox4
    @protox4 Před rokem +1

    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).

  • @dwovitz
    @dwovitz Před rokem

    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.

  • @jeanmartin5271
    @jeanmartin5271 Před rokem

    Hi, in fact I didn't know about async void, always used async Task. Thanks.

  • @NicholasStein
    @NicholasStein Před rokem

    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.

  • @ApacheSenior
    @ApacheSenior Před rokem

    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.

  • @AnotherFancyUser
    @AnotherFancyUser Před rokem +1

    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.

  • @pavelkravchenko2810
    @pavelkravchenko2810 Před rokem

    Hi, Nick. Can you make course about grpc in dotnet?

  • @djenning90
    @djenning90 Před rokem

    Long running background tasks… yes, interested!

  • @RusslanK
    @RusslanK Před rokem

    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();

  • @RossBawden
    @RossBawden Před rokem

    Please do a video on long-running background tasks!

  • @marcusarmijo2239
    @marcusarmijo2239 Před rokem

    I'd like to see the long running task video as well

  • @tracetv8115
    @tracetv8115 Před rokem

    Can u make a tutorial/video about „exception handling best practices“?

  • @BillyBraga
    @BillyBraga Před rokem +1

    What is the difference between
    bgTask.RunAsync()
    and
    Task.Run(async => await bgTask.RunAsync())
    ?

  • @ArnonDanon
    @ArnonDanon Před rokem +4

    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.

    • @diadetediotedio6918
      @diadetediotedio6918 Před rokem +3

      Task.Factory.StartNew(..., ...LongRunning)

    • @ArnonDanon
      @ArnonDanon Před rokem

      @@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

  • @alexanderdell2623
    @alexanderdell2623 Před rokem +1

    Hi, it will be pretty cool if you`ll make video about concurrent collections.
    There not so many videos about them on yt

  • @camelCased
    @camelCased Před 7 měsíci

    I'm wondering how Windows forms require button click events to return void, even when they are async.

  • @michaelinsberg2185
    @michaelinsberg2185 Před rokem

    I would like to see a video about long running tasks

  • @Hyp3rSon1X
    @Hyp3rSon1X Před rokem

    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...

  • @abdulmoiz3348
    @abdulmoiz3348 Před rokem

    yes pleeease, 2 things i really need to understand:
    1. long running background tasks.
    2. .ConfigureAwait(false)

  • @brianm1864
    @brianm1864 Před rokem +1

    I agree with others... I would like to see a video on long-running background tasks

  • @keke772
    @keke772 Před rokem +3

    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?

    • @keke772
      @keke772 Před rokem

      In MAUI I use MainThread.InvokeOnMainThreasAsync

    • @ghevisartor6005
      @ghevisartor6005 Před rokem

      Use PeriodicTimer, you can do
      while(await timer.WaitNextTickAsync())
      await callback()
      Or something like this?

    • @keke772
      @keke772 Před rokem

      @@ghevisartor6005 I am doing this but to make the loop run in background I wrap that logic on a async void method

    • @ghevisartor6005
      @ghevisartor6005 Před rokem

      @@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.

  • @nove1398
    @nove1398 Před rokem

    Usually in Task.Run(t => task). I would like to see long running task video.

  • @xmetax
    @xmetax Před rokem

    I stopped using async void ever since your first video warning about it's potential dangers

  • @tancyew
    @tancyew Před rokem

    is there any cons in using async void if we were to put try catch in it? any performance impact or whatsoever?

    • @okcharles7
      @okcharles7 Před rokem +1

      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.

    • @diadetediotedio6918
      @diadetediotedio6918 Před rokem +1

      Just trying consumes almost nothing, but the catching part is actually the problem

    • @taemyr
      @taemyr Před rokem +1

      The method knows what it is doing, but not why this is done. This might prevent meaningful handling of the exception.

  • @Yannici
    @Yannici Před rokem

    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?

    • @ghevisartor6005
      @ghevisartor6005 Před rokem

      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.

    • @Yannici
      @Yannici Před rokem +1

      @@ghevisartor6005 Oh... Damn I don't know why I had problems with it... You are absolutely right, I tried it. Sorry ;-)

    • @ghevisartor6005
      @ghevisartor6005 Před rokem

      @@Yannici no problem sometimes it's even the compiler giving false errors

  • @anderskehlet4196
    @anderskehlet4196 Před rokem +2

    CC: "hello everybody I'm naked in this video"
    Well, that was a lie. :(

  • @mikebarber1
    @mikebarber1 Před rokem

    Another request for covering long running tasks

  • @billy65bob
    @billy65bob Před rokem

    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`...

  • @lukasssss4604
    @lukasssss4604 Před rokem

    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... 🙈

  • @olegvorkunov5400
    @olegvorkunov5400 Před rokem +1

    Would global error handler prevent from application crash?

    • @AnotherFancyUser
      @AnotherFancyUser Před rokem

      Some sort of middleware? that is a good question.

    • @olegvorkunov5400
      @olegvorkunov5400 Před rokem

      @@AnotherFancyUser Even in console app: AppDomain.CurrentDomain.UnhandledException. I prefer never use try/catch in my code.

    • @niveliyahu146
      @niveliyahu146 Před rokem

      @@AnotherFancyUser thous will help to to do some last things before crash like log the error but will not prevent the crash because your application is already lost the context

  • @lorddraagon
    @lorddraagon Před rokem +1

    Oh learned this the hard way. In production xD

  • @ivandrofly
    @ivandrofly Před rokem

    Do a Video on long running background

  • @goblelol
    @goblelol Před rokem +2

    What about '_ = bgTask().ContinueWith((t) => { if (t.IsFaulted) { // here we have t.Exception of type AggregateException, having all exceptions occured in background } });

    • @nickchapsas
      @nickchapsas  Před rokem

      Rolls off the tongue

    • @ehvlullo
      @ehvlullo Před rokem

      I also like it better. Task.Run() is pretty overused imho

  • @nanvlad
    @nanvlad Před rokem +1

    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

    • @FudgeYeahLinusLAN
      @FudgeYeahLinusLAN Před rokem

      Probably because WPF is utter trash and always has been.

    • @LeMustache
      @LeMustache Před rokem

      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.

  • @oleksandrdubyna4173
    @oleksandrdubyna4173 Před rokem

    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

  • @dragonyt73
    @dragonyt73 Před rokem

    Long-running background task!!

  • @rick2591
    @rick2591 Před rokem

    I have never used asynch void. I have never even thought of using this.

  • @joschemd
    @joschemd Před rokem

    What do you do when you have no other choice (like in unity?)

  • @user-rt9kn9cm8l
    @user-rt9kn9cm8l Před měsícem

    Thanks, now i know that i did some bugs 🙂

  • @user-wv8xz3vi3l
    @user-wv8xz3vi3l Před rokem

    of cource you MUST using try-catch where possible something can goes wrong! its a base

  • @ReasonForWhile
    @ReasonForWhile Před rokem

    Good content. A remark for improvement: Speak slowly, it will help and improve the message delivery.

  • @VladVolkov76
    @VladVolkov76 Před rokem

    FireAndForget == Thread.
    From my point of view.
    At least for long-running tasks

  • @BillieJoe512
    @BillieJoe512 Před rokem

    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 🤓

  • @StevenCasburn
    @StevenCasburn Před rokem

    public static class TaskExtension
    {
    public static async void FireAndForget(this Task task)
    {
    try { await task; }
    catch { }
    }
    }
    Same approach, just add .FireAndForget() to your async-method-call.

    • @nickchapsas
      @nickchapsas  Před rokem +1

      This is wildly different than what I show in the video and it's flawed. Don't use this. You should only deal with tasks that haven't completed or are faulted. Awaiting everything is wasteful. Also ConfigureAwait(false) is missing. Just use the example in the video.

    • @StevenCasburn
      @StevenCasburn Před rokem

      @@nickchapsas Thanks Nick!

  • @pingu2k4
    @pingu2k4 Před rokem

    What about using a discard? `_ = SomeTask();` for example.

    • @protox4
      @protox4 Před rokem

      That doesn't prevent UnobservedTaskException, that just tells the C# analyzer to stop warning you about it.

    • @protox4
      @protox4 Před rokem

      @@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.

  • @DeznekCZ
    @DeznekCZ Před rokem

    This behaviour is seen in many languages 🙂
    Asynchronous things are always complicated.

  • @auronedgevicks7739
    @auronedgevicks7739 Před 3 měsíci

    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.

  • @DiegoMenta
    @DiegoMenta Před rokem

    Long running tasks!!

  • @maestrowilliam
    @maestrowilliam Před rokem

    //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);
    }

  • @LCTesla
    @LCTesla Před 8 měsíci

    I'm appalled the compiler even allows async void. I would never write something like that intentionally.

  • @AQDuck
    @AQDuck Před rokem

    Wait, list.ForEach is a thing?...

  • @derangedftw
    @derangedftw Před rokem

    Ahh Tasks, thank God for Stephen Cleary many years ago.

  • @mehmetck
    @mehmetck Před rokem

    When i saw this video i said that Stephen toub is coming 😂

  • @TOKYODRIFT00000
    @TOKYODRIFT00000 Před rokem

    sometimes async void is good

  • @chswin
    @chswin Před rokem

    You could just pass a waithandle to it and wait for it to finish…