如何使异步 httpclient web *response* 处理到以后(计算后)



我做了一个httpclient调用,然后想立即开始计算。我不希望计算受到返回响应的干扰。计算最多可能需要 3 秒。

伪代码

{
var data = await GetDataFromCloud();
//do calculations - highly time sensitive!
DoCalc() //A recursive job or nested loop *the response is occurring within this call :(
//I want the response to occur here after the work above has completed :)
}

会在这里锁定工作。 此代码位于 UI 线程上的异步函数内。 DoCalc 是非阻塞的。UI 线程未被阻止。

假设您不需要从GetDataFromCloud()返回的数据来实际执行计算,您可以从方法中获取任务而不是等待它,进行计算,然后等待它。

像这样:

{
var dataTask = GetDataFromCloud(); // Starts the task and returns it
//do calculations - highly time sensitive!
DoCalc()
var data = await dataTask; // Wait for the task to finish (if it hasn't already)
}

当然,如果计算需要数据,那么您要么需要等待所有数据先下载,要么通过抓取 HttpResponseMessage 并手动读取内容来处理"数据流"。

编辑:

还值得注意的是,如果请求中出现问题(即抛出异常),使用这种方法直到await才会知道它。

这正是我们想要使用 async-await 的场景!

当您的线程必须空闲地等待其他事情完成时,异步等待很有用。例如,要读取的文件、要执行的数据库查询、要下载的网页。通常,其他人正在执行工作,而您的线程只是在等待工作完成。

您可以"执行其他操作而不是闲置等待"的函数被声明为异步。请参阅读取文件时的Stream.ReadAsync、执行数据库查询时的Dapper.SQLMapper.QueryAsync、实体框架中数据库查询的ToListAsyncFirstOrDefaultAsync、互联网下载WebClient.DownloadFileAsync等。

如果调用异步函数,则返回值是Task而不是void,或者返回值是Task<TResult>而不是TResult。有一个例外:事件处理程序不会生成任务,而是无效。

如果你想从 async-await 中受益,你必须定义你的函数 async 并返回一个TaskTask<TResult>

调用异步函数时,可以确定此函数中的某个位置是等待。事实上,如果你忘记在某个地方等待,你的编译器会警告你。同样,如果您定义了函数异步但忘记调用另一个异步函数,则会收到警告

调用另一个异步函数后,只要不需要调用的结果,就可以继续工作。一旦您需要结果,您就可以等待任务。

如果您开始等待任务,但数据仍然不可用,则您的线程将向上调用其调用堆栈,以查看您的调用方是否有事情要做,直到您的调用方等待。再次向上调用堆栈以查看是否有工作要做,等等。

async Task<MyResult> GetMyData(...)
{
Task<SomeData> taskGetData = GetDataFromCloud(...);
// while the data is being fetched, we can continue working
DoSomethingElse();
// now we need the data:
SomeData fetchedData = await taskGetData;
MyResult result = ProcessFetchedData(fetchedData);
return result;
}

帮助我理解异步等待的是这次对Eric Lippert的采访。在中间的某个地方搜索异步等待。

对我有帮助的是这篇由一直乐于助人的斯蒂芬·克利里(Stephen Cleary)撰写的文章。

最新更新