Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async Sub() Or Async Function() As Task for Fire and Forget?

I want to do something asynchronously and don't care for the result.
What is the best way to do that?

Public Async Function HandlerForSomeEvent() As Task
  'This is where I do stuff

  'Then this is stuff I want to do without waiting for it
  DoStuff()

  'Here I continue doing other stuff
End Function
Async Sub DoStuff()
  'Doing stuff while the handler continues doing it's stuff
End Sub

'VS

Async Function DoStuff() As Task
  'Doing stuff while the handler continues doing it's stuff
End Function

Everyone tells me to use Function As Task, but as I don't await it I always get the annoying warning in VS.
What is the difference and why should I do it?

like image 702
Fox Avatar asked Sep 05 '25 05:09

Fox


1 Answers

The big reasons for using a Function that returns a Task, rather than an Async Sub are two-fold. The first is exception handling. If you do something like this, you'll get an uncaught exception which will terminate your application:

Public Sub Main()
    Try
        DoSomethingAsync()
    Catch ex As Exception
        Console.WriteLine(ex)
    End Try
End Sub

Private Async Sub DoSomethingAsync()
    Throw New Exception()
End Sub

The exception won't get caught by the Try/Catch block, since it's thrown on a separate thread.

However, if you do this, it will get caught and handled:

Public Async Sub Main()
    Try
        Await DoSomethingAsync()
    Catch ex As Exception
        Console.WriteLine(ex)
    End Try
End Sub

Private Async Function DoSomethingAsync() As Task
    Throw New Exception()
End Sub

The second big reason is because, even though you might not need it now, you might need it later. If it's already a function that returns a task, then you can use it either way you wish. If you don't, you can't await on it, or schedule things to happen after it, or abort it, or do any of the other things that you can do with tasks. So, the question really isn't "why do it?", but rather "why not do it?"

For instance, this outputs "Here" followed by "Done":

Public Sub Main()
    DoSomethingAsync()
    Threading.Thread.Sleep(5000)
    Console.WriteLine("Done")
End Sub

Public Async Function DoSomethingAsync() As Task
    Console.WriteLine("Here")
End Function

As others have mentioned, to avoid the warning, you can assign the task to a variable like this:

Public Sub Main()
    Dim t As Task = DoSomethingAsync()
    Threading.Thread.Sleep(5000)
    Console.WriteLine("Done")
End Sub

It works the same either way and runs on its own thread, just like an Async Sub. It doesn't matter if the Task variable goes out of scope either. The task will continue running even if nothing is referencing it. For instance:

Public Sub Main()
    DoSomething()
    Threading.Thread.Sleep(5000)
    Console.WriteLine("Really Done")
End Sub

Public Sub DoSomething()
    Dim t As Task = DoSomethingAsync()
    Console.WriteLine("Done Doing Something")
End Sub

Public Async Function DoSomethingAsync() As Task
    Console.WriteLine("Here")
End Function
like image 92
Steven Doggart Avatar answered Sep 07 '25 20:09

Steven Doggart