究竟发生了什么,而不是等待关键字调用异步方法?
我有一个Web服务器,并有定期作业合并和发送记录(大量的请求日志)。
Task.Run(() =>
{
while (true)
{
try
{
MergeAndPutRecords();
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
});
在MergeAndPutRecords
函数中,有代码合并记录,异步函数返回任务发送记录。 (显然它是亚马逊Kinesis Firehose的PutRecordBatchAsync。)
那么如果我没有等待关键字调用该函数会发生什么? 函数是否在分离的线程上运行? 这里说的不是。 那么什么是返回任务手段? 这里说的是没有等待关键字方式的异步方法
那么我的定期作业和PutRecordBatchAsync是同时处理的吗? 我知道asynchronouse和并发是不同的。 但没有await关键字,它们在同一个线程中。 哪一个会先执行? 我很困惑......
将会有大量的记录需要实时合并和发送。 所以我认为它必须同时执行..
那么我的定期作业和PutRecordBatchAsync是同时处理的吗?
使用Task API可以确保它们并发执行(使用线程池),但是您需要了解内存并发操作与基于IO的并发性之间的差异。
虽然在内存并发中使用任务有益,但是IO调用一旦执行完全不需要线程,因为它依赖于硬件并发性,如果它使用线程,它所做的只是等待IO调用返回,因此浪费宝贵的系统资源并降低系统可扩展性
你的情况是,基于IO的并发性,当你调用基于远程/网络的API时,异步等待在这里有什么帮助?
真正的异步操作将释放线程上下文,在Windows上它将使用IO完成端口(排队机制)来执行异步调用,而调用线程用于调度其他类似的调用,它只需要线程上下文返回用于提供响应的IO调用,如果它不是UI调用,则使用ConfigureAwait(false)
,以便可以使用任何线程上下文来传递响应。
如果你不使用async等待呢?
意图为异步的调用将变为同步,并且会立即影响系统可伸缩性,因为线程现在被阻塞,对于长时间运行的IO操作来说甚至更糟。 你有没有看过JavaScript框架如何总是对服务器API进行AJAX(异步)调用,因此在没有阻止浏览器线程的情况下可以做更多的工作。
一般来说,在内存处理中,您可以创建一定数量的任务,并使用Task.WaitAll
或Parallel.ForEach
处理集合,以进行异步处理,理想情况下建议不要在任何地方拥有Task.Run
,其首选必须为Async
从入口点来看,就像在MVC中可能的情况一样,控制器可以是异步的。 多个呼叫使用Task.WhenAll
代表任务分组在一起,然后等待。 即使您在代码中使用Task.Run
,然后使用async lambda
来执行异步调用
总结:
它必须使用await
来进行异步调用,否则它们的async
关键字在该上下文中没有用处,并且yes await
会在继续执行之前等待IO调用返回,尽管进程中没有线程被阻塞
如果一个方法返回一个Task
,最好的做法是在某个时候观察该Task
的结果。 它可能是声明的返回值,也可能是一个例外。 如果你想在你的方法继续之前观察那个任务,那么await
就是建议。
在这种情况下,您应该可以观察PutRecordBatchAsync
返回的Task
的结果。 你会想知道电话是否因任何原因失败,因为这可能表明你的记录没有被存储!
在您给出的示例代码中,您会发现在前一个调用完成之前,您将对MergeAndPutRecords
进行后续调用。 你确定这是有意的吗?
上一篇: What exactly happens call async method without await keyword?