繁体   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