在没有await关键字的情况下调用async方法究竟发生了什

时间:2017-12-22 08:53:41

标签: c# asynchronous async-await

我有一个Web服务器,并且有定期作业合并和发送记录(许多请求日志)。

Task.Run(() =>
{
    while (true)
    {
        try
        {
            MergeAndPutRecords();
        }
        catch (Exception ex)
        {
            Logger.Error(ex);
        }
    }
});

MergeAndPutRecords函数中,有代码合并记录和异步函数返回任务发送记录。 (实际上它是亚马逊Kinesis Firehose的PutRecordBatchAsync。)

如果我在没有await关键字的情况下调用该函数会发生什么?函数是否在单独的线程上运行? Here says it is not。那么什么是返回任务手段? Here表示没有等待关键字的异步方法意味着

  
      
  1. 在当前线程上启动异步方法。忽略所有结果(包括例外)。
  2.   

然后同时处理我的定期作业和PutRecordBatchAsync?我知道asynchronouse和concurrent是不同的。但是没有await关键字,它们在同一个线程中。首先执行哪一个?我很困惑......

需要合并并实时发送大量记录。所以我认为它必须同时执行..

2 个答案:

答案 0 :(得分:7)

  

然后同时处理我的定期作业和PutRecordBatchAsync?

使用Task API可以确保它们是并发执行的(使用线程池),但是您需要了解内存并发操作与基于IO的并发之间的区别。

虽然在内存并发中确实可以使用Tasks获益,但是一旦执行IO调用根本不需要线程,因为它依赖于硬件并发,如果它曾经使用过该线程,它会做的就是等待IO呼叫返回,从而浪费宝贵的系统资源并降低系统可扩展性

  

你的情况是基于IO的并发性,当你调用基于远程/网络的API时,async-await如何在这里起作用?

确实如此异步操作将释放线程上下文,在Windows上它将使用IO完成端口(排队机制)来执行异步调用,而调用线程用于调度其他类似的调用,它只需要线程上下文在返回IO调用以提供响应时,如果它不是UI调用,则使用ConfigureAwait(false),以便可以使用任何线程上下文来传递响应。

  

如果您没有使用等待异步?

,该怎么办?

调用意味着异步变为同步,并且会立即影响系统可伸缩性,因为线程现在被阻止,对于长时间运行的IO操作来说更糟糕。你有没有看到JavaScript框架如何总是对服务器API进行AJAX(异步)调用,因此可以做更多的工作来阻止浏览器线程。

一般情况下,在内存处理中,您将创建一定数量的任务并使用Task.WaitAllParallel.ForEach处理集合,对于异步处理,理想情况下建议不要{{1}在任何地方,它首选从入口点到Task.Run,就像MVC一样,控制器可以是异步的。使用Async代表任务将多个呼叫组合在一起,然后等待。即使您在代码中使用Task.WhenAll,也请使用Task.Run执行异步调用

  

摘要:

它必须使用async lambda进行异步调用,否则它们await关键字在该上下文中是无用的,而async将等待IO调用在继续执行之前返回,尽管流程中没有阻止任何线程

答案 1 :(得分:0)

如果方法返回Task,则最好在某个时刻观察Task的结果。它可能是声明的返回值,也可能是例外。如果您希望在方法继续之前观察该任务,则建议使用await

在这种情况下,您应该观察Task返回的PutRecordBatchAsync的结果。您可能想知道呼叫是否因任何原因失败,因为这可能表明您的记录未被存储!

在您提供的示例代码中,您会发现在上一次调用完成之前,您将对MergeAndPutRecords进行后续调用。你确定这是有意的吗?