簡體   English   中英

觸發並忘記異步任務方法有時不會調用

[英]fire and forget an async Task method sometimes not invoke

我有一個異步方法:

public async Task DoSomethingAsync(){
    ...
    await ...
    await ...
    ....
    return await SaveAsync();
}

在大多數時候,我通過以下方式調用此方法:

await DoSomethingAsync()

此調用按預期工作。 但在某個地方,我需要將此方法稱為火,並忘記:

public void OtherMethod()
{
    ...
    DoSomethingAsync(); //fire and forget here
}

在這種情況下,有時Task DoSomethingAsync()運行並完成,但有時任務永遠不會被調用(或者在DoSomethingAsync()調用一些await但永遠不會完成最后一次await SaveAsync(); )。

我正在嘗試通過以下代碼確保以火災和忘記方式調用任務:

public void OtherMethod()
{
    ...
    Task.Factory.StartNew(() =>
    {
        await DoSomethingAsync();
    }); //fire and forget again here
}

但是,這不符合預期。 所以我的問題是:

  1. 如何在沒有await情況下調用DoSomethingAsync()將始終運行並完成? (我不關心AppDomain重啟/崩潰的情況)

  2. 如果我刪除所有async/await內碼DoSomethingAsync()和REPLACE await通過.ContinueWith()然后調用Task DoSomethingAsync()沒有async在方法聲明)將被調用,並確保完成(忽略大小寫的AppDomain重新啟動/崩潰),如果是的話,從通話中退出多長時間(我不認為如果在10分鍾后調用任務我會很高興)?

您可能在DoSomethingAsync某處遇到異常,由於您忽略了該任務,因此無法觀察到該異常。 這正是您要求的行為,因為您告訴代碼“忘記”任務。

要觀察異常,你不能“忘記”任務:

public Task OtherMethodAsync()
{
  ...
  return DoSomethingAsync();
}

在某些時候, await (或Wait )返回的任務。 這就是你知道任務將運行和完成的方式。

等待應該工作正常,所以這里可能還有其他東西正在等待你的一個或多個方法。 有幾種可能性:

  1. 你的某個方法中有某個死鎖,阻止它完成並阻止等待恢復。
  2. 由於某種原因,所有線程池線程都被阻塞,導致掛起的任務無法運行。
  3. 您正在同步上下文中運行異步方法,並且正在阻止上下文,從而阻止它運行調度的回調。 通常情況下,上下文將是UI線程,通常這很明顯,因為它會鎖定您的應用程序UI。

如果您可以使用VS調試器附加並觀察發生的情況,請嘗試暫停並查看Parallel Stacks視圖。 這應該有助於縮小考慮的可能性。


正如斯蒂芬指出的那樣,當你稱之為“即發即忘”時,也可能發生異常。 如果您還沒有,請確保處理TaskScheduler.UnobservedTaskException以記錄此類事件。 請注意,這是從終結器調用的,因此調用它的時間是不確定的。 這可能會使調試變得棘手,因為事件可能要比導致異常的實際事件晚得多。 因此,我建議遵循Stephen的建議並將任務保存到等待或稍后等待其他地方。

ASP.NET通常不允許在請求中啟動fire-and-forget(async void)操作。 有關此行為的進一步說明以及一些可能的解決方法,請參閱https://stackoverflow.com/a/22484832/59641

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM