簡體   English   中英

在沒有 await 關鍵字的情況下調用異步方法究竟會發生什么?

[英]What exactly happens call async method without await keyword?

我有一個 Web 服務器,並且有一個定期的作業合並和發送記錄(大量請求日志)。

Task.Run(() =>
{
    while (true)
    {
        try
        {
            MergeAndPutRecords();
        }
        catch (Exception ex)
        {
            Logger.Error(ex);
        }
    }
});

MergeAndPutRecords函數中,有代碼合並記錄和 async 函數返回 Task 發送記錄。 (實際上它是 Amazon Kinesis Firehose 的PutRecordBatchAsync 。)

那么如果我在沒有 await 關鍵字的情況下調用該函數會發生什么? 函數是否在單獨的線程上運行? 這里說不是 那么什么是返回Task Means呢? 這里說沒有 await 關鍵字的異步方法意味着

  1. 在當前線程上啟動異步方法。 忽略所有結果(包括異常)。

那么我的定期作業和 PutRecordBatchAsync 是並發處理的嗎? 我知道異步和並發是不同的。 但是沒有 await 關鍵字並且它們在同一個線程中。 哪個會先被處決? 我很困惑...

會有大量記錄需要實時合並和發送。 所以我認為它必須同時執行..

那么我的定期作業和 PutRecordBatchAsync 是並發處理的嗎?

使用 Task API,您可以確保它們並發執行(使用線程池),但您需要了解內存並發操作與基於 IO 的並發之間的區別。

雖然內存並發使用任務確實有好處,但一旦執行 IO 調用根本不需要線程,因為它依賴於硬件並發,如果它曾經使用過線程,它會等待 IO 調用返回,因此浪費寶貴的系統資源,降低系統的可擴展性

您的情況是基於 IO 的並發性,當您調用基於遠程/網絡的 API 時,async-await 在這里有何幫助?

嗯,真正的異步操作會釋放線程上下文,在 Windows 上它將使用 IO 完成端口(排隊機制)來執行異步調用,而調用線程用於調度其他類似的調用,它只需要返回線程上下文用於提供響應的 IO 調用,如果它不是 UI 調用,則使用ConfigureAwait(false) ,以便可以使用任何線程上下文來傳遞響應。

如果不將 await 與 async 一起使用怎么辦?

本來是異步的調用變成了同步的,並且會立即影響系統的可擴展性,因為線程現在被阻塞了,對於長時間運行的 IO 操作甚至更糟。 您是否看到 JavaScript 框架總是對服務器 API 進行 AJAX(異步)調用,因此可以在不阻塞瀏覽器線程的情況下完成更多工作。

一般來說,對於內存處理,您將創建一定數量的任務並使用Task.WaitAllParallel.ForEach處理它們作為集合,對於異步處理,理想情況下建議不要在任何地方使用Task.Run ,它首選必須Async從入口點開始,就像在 MVC 的情況下一樣,控制器可以是異步的。 使用Task.WhenAll代表 Task 將多個調用組合在一起,然后等待。 即使您在代碼中使用Task.Run ,然后使用async lambda執行異步調用

概括 :

必須將await用於異步調用,否則它們async關鍵字在該上下文中是無用的,是的await將在繼續執行之前等待 IO 調用返回,盡管進程中沒有線程被阻塞

如果一個方法返回一個Task ,最好在某個時刻觀察該Task的結果。 它可能是聲明的返回值,也可能是一個異常。 如果您想在方法繼續之前觀察該任務,建議使用await

在這種情況下,您可能應該觀察PutRecordBatchAsync返回的Task的結果。 您會想知道呼叫是否因任何原因失敗,因為這可能表明您的記錄未存儲!

在您提供的示例代碼中,您會發現您在前一次調用完成之前對MergeAndPutRecords進行了后續調用。 你確定這是故意的嗎?

暫無
暫無

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

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