简体   繁体   English

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

[英]What exactly happens call async method without await keyword?

I have a web server and there is a periodic job merges and send records (lots of request logs).我有一个 Web 服务器,并且有一个定期的作业合并和发送记录(大量请求日志)。

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

In MergeAndPutRecords function, there are code merging records and async function returns Task sending records.MergeAndPutRecords函数中,有代码合并记录和 async 函数返回 Task 发送记录。 (Actaully it is Amazon Kinesis Firehose's PutRecordBatchAsync .) (实际上它是 Amazon Kinesis Firehose 的PutRecordBatchAsync 。)

Then what happens if i call that function without await keyword?那么如果我在没有 await 关键字的情况下调用该函数会发生什么? Does function runs on seperated thread?函数是否在单独的线程上运行? Here says it is not . 这里说不是 Then what is returning Task Means?那么什么是返回Task Means呢? Here says async method without await keyword means 这里说没有 await 关键字的异步方法意味着

  1. Starts the asynchronous method on the current thread.在当前线程上启动异步方法。 Ignores all results (including exceptions).忽略所有结果(包括异常)。

Then my periodic job and PutRecordBatchAsync are processed concurrently?那么我的定期作业和 PutRecordBatchAsync 是并发处理的吗? I know asynchronouse and concurrent is different.我知道异步和并发是不同的。 But there is no await keyword and they are in same thread.但是没有 await 关键字并且它们在同一个线程中。 Which one would be executed first?哪个会先被处决? I'm confusing...我很困惑...

There would be massive records that needs to be merge and sent in real-time.会有大量记录需要实时合并和发送。 So I think it must be executed concurrently..所以我认为它必须同时执行..

Then my periodic job and PutRecordBatchAsync are processed concurrently?那么我的定期作业和 PutRecordBatchAsync 是并发处理的吗?

Using Task API you can ensure that they are executed concurrently (using Thread pool), but you need to understand the difference between in memory concurrent operations Vs IO based concurrency.使用 Task API,您可以确保它们并发执行(使用线程池),但您需要了解内存并发操作与基于 IO 的并发之间的区别。

While In memory concurrency does benefit using Tasks, IO call once executed doesn't need thread at all, as it relies on hardware concurrency, if it ever use the thread, all that it would do it wait for the IO call to return, thus wasting the precious system resources and reducing system scalability虽然内存并发使用任务确实有好处,但一旦执行 IO 调用根本不需要线程,因为它依赖于硬件并发,如果它曾经使用过线程,它会等待 IO 调用返回,因此浪费宝贵的系统资源,降低系统的可扩展性

You case is that IO based concurrency, as you call a remote / network based API, how does async-await helps here ?您的情况是基于 IO 的并发性,当您调用基于远程/网络的 API 时,async-await 在这里有何帮助?

Well true Async operation will free up the thread context, on windows it would use IO completion port (queuing mechanism) to execute the Async call, while the calling thread is used to dispatch other similar calls, it would just need thread context on return of the IO call for serving the response and for that too, if its not a UI call, then use ConfigureAwait(false) , so that any thread context can be used to deliver the response.嗯,真正的异步操作会释放线程上下文,在 Windows 上它将使用 IO 完成端口(排队机制)来执行异步调用,而调用线程用于调度其他类似的调用,它只需要返回线程上下文用于提供响应的 IO 调用,如果它不是 UI 调用,则使用ConfigureAwait(false) ,以便可以使用任何线程上下文来传递响应。

What if you don't use await with async ?如果不将 await 与 async 一起使用怎么办?

The call meant to be Asynchronous becomes Synchronous and would immediately impact the system scalability, as threads are now blocked, even worse for a long running IO operations.本来是异步的调用变成了同步的,并且会立即影响系统的可扩展性,因为线程现在被阻塞了,对于长时间运行的 IO 操作甚至更糟。 Have you seen how JavaScript frameworks always make a AJAX (Async) call to the server API, thus much more work is possible W/o blocking the Browser threads.您是否看到 JavaScript 框架总是对服务器 API 进行 AJAX(异步)调用,因此可以在不阻塞浏览器线程的情况下完成更多工作。

In general for In memory processing you would create certain number of Tasks and process them using Task.WaitAll or Parallel.ForEach for a collection, for Async processing, ideally recommendation is not to have a Task.Run anywhere, its preferred to have to Async from the entry point, like its possible in case of MVC, controllers can be async.一般来说,对于内存处理,您将创建一定数量的任务并使用Task.WaitAllParallel.ForEach处理它们作为集合,对于异步处理,理想情况下建议不要在任何地方使用Task.Run ,它首选必须Async从入口点开始,就像在 MVC 的情况下一样,控制器可以是异步的。 Multiple calls are grouped together using Task.WhenAll representative Task and then awaited upon.使用Task.WhenAll代表 Task 将多个调用组合在一起,然后等待。 even if you use Task.Run as in your code, then use async lambda to execute an asynchronous call即使您在代码中使用Task.Run ,然后使用async lambda执行异步调用

Summary :概括 :

Its mandatory to use await for asynchronous calls, else they async keyword is useless in that context and yes await will wait for the IO call to return before continuation is executed, though no thread is blocked in the process必须将await用于异步调用,否则它们async关键字在该上下文中是无用的,是的await将在继续执行之前等待 IO 调用返回,尽管进程中没有线程被阻塞

If a method returns a Task , it is always best practice to observe the result of that Task at some point.如果一个方法返回一个Task ,最好在某个时刻观察该Task的结果。 It may be the declared return value, or it may be an exception.它可能是声明的返回值,也可能是一个异常。 If you want to observe that task before your method continues, await is the recommendation.如果您想在方法继续之前观察该任务,建议使用await

In this case, you should probably be observing the result of the Task returned by PutRecordBatchAsync .在这种情况下,您可能应该观察PutRecordBatchAsync返回的Task的结果。 You will want to know if the call failed for any reason as this probably indicates that your records were not stored!您会想知道呼叫是否因任何原因失败,因为这可能表明您的记录未存储!

In the example code you gave, you will find that you make subsequent calls to MergeAndPutRecords before the previous call is complete.在您提供的示例代码中,您会发现您在前一次调用完成之前对MergeAndPutRecords进行了后续调用。 Are you sure that this is intended?你确定这是故意的吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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