C# 在没有wait关键字的情况下调用异步方法会发生什么?
我有一个web服务器,有一个定期的作业合并和发送记录(大量请求日志) 在C# 在没有wait关键字的情况下调用异步方法会发生什么?,c#,asynchronous,async-await,C#,Asynchronous,Async Await,我有一个web服务器,有一个定期的作业合并和发送记录(大量请求日志) 在MergeAndPutRecords函数中,有代码合并记录,异步函数返回任务发送记录。(事实上,这是亚马逊动力消防队的。) 那么,如果我在没有wait关键字的情况下调用该函数,会发生什么呢?函数是否在单独的线程上运行。那么返回任务意味着什么?表示不带wait关键字的异步方法 在当前线程上启动异步方法。忽略所有结果(包括异常) 那么我的定期作业和PutRecordBatchAsync是否同时处理?我知道异步和并发是不同的。但并
MergeAndPutRecords
函数中,有代码合并记录,异步函数返回任务发送记录。(事实上,这是亚马逊动力消防队的。)
那么,如果我在没有wait关键字的情况下调用该函数,会发生什么呢?函数是否在单独的线程上运行。那么返回任务意味着什么?表示不带wait关键字的异步方法
将有大量记录需要合并并实时发送。因此,我认为它必须同时执行。如果一个方法返回一个
任务
,最好的做法是在某个点观察该任务的结果。它可能是声明的返回值,也可能是异常。如果要在方法继续之前观察该任务,建议使用wait
在这种情况下,您可能应该观察由PutRecordBatchAsync
返回的任务的结果。您需要知道呼叫是否因任何原因失败,因为这可能表明您的记录未存储
在您给出的示例代码中,您会发现在上一次调用完成之前,您对MergeAndPutRecords
进行了后续调用。你确定这是有意的吗
那么我的定期作业和PutRecordBatchAsync是否同时处理
通过使用任务API,您可以确保它们是并发执行的(使用线程池),但您需要了解内存中并发操作与基于IO的并发之间的区别
虽然内存中的并发性确实有利于使用任务,但IO调用一旦执行就根本不需要线程,因为它依赖于硬件并发性,如果它使用线程,那么它将等待IO调用返回,从而浪费宝贵的系统资源并降低系统可伸缩性
您的案例是基于IO的并发,正如您调用基于远程/网络的API一样,异步如何在这里等待帮助
真正的异步操作将释放线程上下文,在windows上,它将使用IO完成端口(队列机制)执行异步调用,而调用线程用于调度其他类似调用,它只需要在IO调用返回时使用线程上下文来服务响应,如果不是UI调用,然后使用ConfigureAwait(false)
,以便可以使用任何线程上下文来传递响应
如果不将wait与async一起使用呢
本来是异步的调用会变成同步的,并且会立即影响系统的可伸缩性,因为线程现在被阻塞,对于长时间运行的IO操作来说更糟。您已经看到JavaScript框架如何始终对服务器API进行AJAX(异步)调用,因此在阻止浏览器线程的情况下可能需要做更多的工作
一般来说,对于内存处理,您会创建一定数量的任务,并使用Task.WaitAll
或并行处理它们。ForEach
对于集合,对于异步处理,理想的建议是不要有任务。在任何地方运行,最好从入口点开始执行异步,与MVC一样,控制器可以是异步的。多个呼叫使用Task.whalll
representative Task组合在一起,然后等待。即使使用了Task.Run
,也要像在代码中一样,然后使用async lambda
执行异步调用
总结:
异步调用必须使用await
,否则它们的async
关键字在该上下文中是无用的,yesawait
将在继续执行之前等待IO调用返回,尽管进程中没有线程被阻止async
关键字本身不做任何事情。每个wait
组合成一个asynchStateMachine
,可以异步处理内容。如果在async
方法中没有await
关键字,那么就没有理由创建AsyncStateMachine
,所以就得到了同步方法。await
用于等待结果到达。它不以任何方式控制获取结果的进程是如何启动的,也不控制获取结果的正在进行的进程是如何工作的。“原本是异步的调用会变成同步的,并且会立即影响系统的可伸缩性,因为线程现在被阻塞”-我认为这是不正确的或不清楚的。是的,对异步函数的调用是同步返回的,但从概念上讲它总是同步返回;异步性在wait语句中“发生”。如果wait不存在,则调用方将无序地通过异步函数。如果任务有延续,它仍然运行,但实际上是无头的;结果和异常被忽略。(1/3)让我们在正确的上下文中理解该语句,IO调用异步处理的本质是将处理转移到后台,不阻塞任何等待后台进程完成的进程线程,从而确保更高的可伸缩性,因为在windows中,每次执行都发生在线程上,空闲等待是非常不可取的。wait
所做的是创建一个状态机,它捕获当前的执行上下文,用于后续返回。在一系列方法调用中,实际的异步处理在调用离开进程边界(2/3)时开始,在此之前,我们希望每次调用都是这样
Task.Run(() =>
{
while (true)
{
try
{
MergeAndPutRecords();
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
});