使用Async Sub()还是Async Function()作为Fire and Forget的任务?

3

我想异步执行某些操作,但不关心结果。有什么最好的方法吗?

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

所有人都告诉我要使用Function As Task,但是如果我没有使用await,我总是会在VS中收到讨厌的警告。
有什么区别,为什么我应该这样做呢?


1
https://dev59.com/qGct5IYBdhLWcg3wXsQy, https://msdn.microsoft.com/en-us/magazine/jj991977.aspx - GSerg
Async Sub 仅用于事件处理程序。如果它确实是一个事件处理程序,则应该使用 Async Sub,但事件处理程序还应具有适当的参数。如果不是事件处理程序,则不应该使用 Async Sub - jmcilhinney
@GSerg 这是C#。 - Fox
1
@Fox 那并不重要。 - GSerg
@GSerg 你确定吗? - Fox
显示剩余10条评论
1个回答

4

使用返回 TaskFunction,而不是 Async Sub 的主要原因有两个。第一个原因是异常处理。如果你像下面这样做,将会得到一个未捕获的异常,导致应用程序终止:

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

由于异常是在单独的线程上抛出的,因此 Try/Catch 块无法捕获它。

但是,如果使用以下代码,则可以捕获和处理异常:

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

第二个重要原因是,即使你现在不需要它,将来你可能会需要。如果它已经是一个返回任务的函数,那么你可以随意使用它。如果不是,则无法对其进行等待、安排后续操作、中止或执行其他任务。所以,问题实际上不是“为什么这样做?”,而是“为什么不这样做呢?”
例如,以下代码将输出“Here”,然后是“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

正如其他人提到的那样,为了避免警告,您可以像这样将任务分配给变量:

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

这两种方式的工作方式相同,并且在其自己的线程上运行,就像 Async Sub 一样。即使 Task 变量超出了范围,也不会影响任务继续运行。例如:

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

1
当我等待它时,我的处理程序会停止。这就是关键所在。我想同时做两件事情。 - Fox
2
你不必等待异步函数完成。只需将其返回的 Task 分配给一个变量,然后稍后可以使用该变量,例如测试 IsFaulted 来查看其中是否抛出了异常。 - jmcilhinney
@jmcilhinney,问题在于我不能在事件处理程序本身中使用长时间运行的代码。我不能超过3秒。异步操作需要超过10秒。当我将任务分配给一个变量时,我仍然需要稍后等待它们完成,对吧? - Fox
@Fox 不,如果您不等待任务,它仍然会自行运行,就像“Async Sub”一样。等待是可选的。 - Steven Doggart
@Fox,我更新了我的答案,并添加了几个例子。 - Steven Doggart
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接