[英]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.