[英]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 關鍵字的異步方法意味着
- 在當前線程上啟動異步方法。 忽略所有結果(包括異常)。
那么我的定期作業和 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.WaitAll
或Parallel.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.