簡體   English   中英

帶有 HttpClient 的異步任務

[英]async Task with HttpClient

public async Task<IReadOnlyCollection<OrderItem>> GetOrderItemsAsync()
{
    var items = await httpClient.GetFromJsonAsync<IReadOnlyCollection<CatalogItemDto>>("items");
    return items;
}

我有一個具有異步HttpClient的異步Task方法。 HttpClient和 async Task如何協同工作?

我確實知道什么是異步任務,但是結合上面的例子,我想知道它在幕后是如何工作的。

請幫助我了解幕后的細節。 目前,每當我看到異步Task時,我只是在不知道內部編譯器如何執行的情況下等待。

一個正確但也有點無用的答案是: async/await在后台創建 state 機器。

但我們可以做得更好。 讓我們從什么是任務開始。 這是一個 object,其中包含一些 function 應該在將來的某個時間點調用(作為對某些事件的反應)。 如果 function 返回某些內容(或引發異常),則結果將存儲在 Task 中以供以后使用。

為了執行這些任務,您需要一個 TaskScheduler。 這是一些 object,它決定何時、如何以及執行哪些任務、在哪些線程上、對哪些事件做出反應等。例如,如果我們有一個從磁盤讀取並返回任務的方法,那么它開始從磁盤讀取,它立即返回一個Task,並告訴TaskScheduler“嘿,一旦我從磁盤讀取完畢,為我執行這個Task,好嗎?”。 因此,從磁盤讀取的操作發生在后台(畢竟是 i/o),同時 CPU 可以自由地做其他事情。

Tasks 的另一個特點是它們可以被鏈接。 意思是,我們可以將一個新任務附加到舊任務上,這將在舊任務完成后執行。 在過去,我們會這樣做:

// Say these two are given.
Task<User> GetUserByEmail(string email);
Task<List<Order>> GetOrdersForUser(int userId);

Task<List<Order>> GetOrdersByEmail(string email)
{
    var tcs = new TaskCompletionSource<List<Order>>();

    GetUserByEmail(email)  // T1
        .ContinueWith((prevTask) =>
        {
            // This will be executed only when T1 is done.
            GetOrdersForUser(prevTask.Result.Id)  // T2
                .ContinueWith((prevTask) =>
                {
                    // This will be executed when T2 is done.
                    tcs.TrySetResult(prevTask.Result);
                });
        });

    return tcs.Task;
}

但是人們意識到,當發生大量異步調用時,這種編碼很快就會變得不可讀。 這也稱為“回調地獄”(取自 JavaScript 的術語)。

async/await所做的只是解決了這個可讀性問題。 事實上,通過應用它,上面的代碼可以重寫為:

async Task<List<Order>> GetOrdersByEmail(string email)
{
    var user = await GetUserByEmail(email);
    return await GetOrdersForUser(user.Id);
}

好多了,你不覺得嗎? 從技術上講,這些是不一樣的(我沒有在“回調地獄”版本中進行任何錯誤處理,這會使情況變得更糟)。 編譯器實際上為async/await生成了不同的代碼(所謂的異步 state 機器,例如,您可以通過查看https://sharplab.io/來了解它的工作原理),但在功能上它們非常接近。

async/await的全部意義在於讓代碼更簡潔。 這是一個句法特征。

我有一個具有同步HttpClient的異步Task方法。

HttpClient既不是同步的也不是異步的。 只有方法可以是同步的或異步的。 而你使用GetFromJsonAsync的具體方法是異步的,它甚至名稱中都有Async :) 好吧,它不一定是異步的(這實際上取決於實現,實際上您可以編寫一個返回已完成任務的同步代碼),但它確實返回了一個我們可以等待的 Task。

暫無
暫無

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

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