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

YB *_* Yu 9 c# asynchronous async-await

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

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

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

如果我在没有await关键字的情况下调用该函数会发生什么?函数是否在单独的线程上运行?这里说它不是.那么什么是返回任务手段?这里说async方法没有等待关键字的意思

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

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

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

Mri*_*boj 7

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

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

虽然In内存并发确实有利于使用Tasks,但一旦执行IO调用根本不需要线程,因为它依赖于硬件并发,如果它曾经使用过该线程,那么它所做的就是等待IO调用返回,因此浪费宝贵的系统资源,降低系统可扩展性

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

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

如果你不使用等待异步怎么办?

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

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

摘要:

它必须await用于异步调用,否则它们的async关键字在该上下文中是无用的,yes await将等待IO调用在执行continuation之前返回,尽管在该过程中没有阻塞线程

  • “本来是异步的调用变成了同步,并且会立即影响系统的可扩展性,因为线程现在被阻止了” - 我认为这要么不正确,要么不清楚。是的,对 async 函数的调用是同步返回的,但从概念上讲它总是如此;异步性“发生”在await 语句中。如果await不存在,调用者将无序地继续执行异步函数。如果任务有延续,它仍然运行,但实际上是无头的;结果和异常被忽略。 (2认同)
  • 我不明白你所说的“好处”会消失。如果我们知道不需要等待该方法,那么我们就不会因为不等待它而降低可伸缩性。请注意,问题是关于异步方法,而不是异步调用。如果一个异步方法取出垃圾并保证在一个小时内完成,并且返回值是垃圾被取出时的气味,那么每周一次“解雇并忘记”该任务是完全可以接受的,如果我们觉得它符合我们的要求。 (2认同)
  • @MrinalKamboj 除非您使用“Task.Run()”,否则不会使用 ThreadPool。删除“await”会在当前线程上启动异步方法。忽略所有结果(包括异常)。- 请参阅此处:/sf/answers/3237206311/ (2认同)