簡體   English   中英

有/無等待的異步/等待(即發即忘)

[英]Async/await with/without awaiting (fire and forget)

我有以下代碼:

static async Task Callee()
{
    await Task.Delay(1000);
}

static async Task Caller()
{
    Callee(); // #1 fire and forget
    await Callee(); // #2 >1s
    Task.Run(() => Callee()); // #3 fire and forget
    await Task.Run(() => Callee()); // #4 >1s
    Task.Run(async () => await Callee()); // #5 fire and forget
    await Task.Run(async () => await Callee()); // #6 >1s
}

static void Main(string[] args)
{
    var stopWatch = new Stopwatch();
    stopWatch.Start();
    Caller().Wait();
    stopWatch.Stop();
    Console.WriteLine($"Elapsed: {stopWatch.ElapsedMilliseconds}");
    Console.ReadKey();
}

#1 以最簡單的方式觸發和遺忘。 #2 只是等待。 有趣的東西從#3 開始。 調用背后的深層邏輯是什么?

我知道在 ASP.NET 中使用 fire'n'forget 警告,如這里所指出的。 我問這個,因為我們正在將我們的應用程序移動到服務結構,在那里我們不再可以使用HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => await LongMethodAsync()); 建議是簡單地用Task.Run替換它。

我看到Task.Run運行一個新線程,那么 #3 和 #5 之間有什么區別?

我問這個,因為我們正在將我們的應用程序移動到服務結構,在那里我們不再可以使用 HostingEnvironment.QueueBackgroundWorkItem(asyncCancellationToken => await LongMethodAsync()); 建議是簡單地用 Task.Run 替換它。

這是個糟糕的建議。 您應該使用一個單獨的后台進程,通過隊列與您的 Web 前端分開

調用背后的深層邏輯是什么?

  1. 在當前線程上啟動異步方法。 忽略所有結果(包括異常)。
  2. 在當前線程上啟動異步方法。 異步等待它完成。 這是調用異步代碼的標准方式。
  3. 在線程池線程上啟動異步方法。 忽略所有結果(包括異常)。
  4. 在線程池線程上啟動異步方法。 異步等待它完成。
  5. 與#3 完全相同。
  6. 與#4 完全相同。

“26.《Fire and Forget》很好,只要你永遠不會真正忘記。” 馬克西姆 26

如果您執行任何類型的火災並忘記場景,您將面臨吞咽異常的巨大風險。 吞下任何異常——尤其是致命的——是異常處理的致命罪過。 你最終得到的只是內存中的一個程序,它會產生更難以理解和可重現的異常。 所以永遠不要開始。 這是有關該材料的兩篇不錯的文章:

http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in -網

Full on Threads 能夠吞下異常是出了名的。 事實上,你必須努力不吞下它們,然后在它們完成后檢查它們是否有。 您應該至少有一些后續任務來記錄(和可能的暴露)異常。 否則你真的會后悔那個“火了就忘”。

希望有幫助。

暫無
暫無

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

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