繁体   English   中英

在没有 await 关键字的情况下调用异步方法究竟会发生什么?

[英]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 关键字的异步方法意味着

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

那么我的定期作业和 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.WaitAllParallel.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM