在 Task.Run 中进行异步调用是不好的做法吗?

Qua*_*ade 1 c# task async-await .net-core

我有一个 C# 控制台应用程序,每 1 分钟处理来自 RabbitMQ 的大约 100,000 条 JSON 消息

从 RabbitMQ 获取每条/一堆消息后,我然后调用

 await Task.Run(async () =>
 {
    //do lots of CPU stuff here, including 2 external API calls using await async call
 }
Run Code Online (Sandbox Code Playgroud)

我读过的所有内容都说使用awaitTask.Run进行CPU 密集型操作。并用于await asyncHTTP外部调用。

如果我把它改成:

await Task.Run(() =>
Run Code Online (Sandbox Code Playgroud)

然后它会抱怨,因为我async在下面的行中有一个 API 调用,所以它需要语句async中的关键字Task.Run

本节大约有 2000 多行代码(复杂的 if then 业务规则),有时不需要 API 调用。

因此,我面临着要么对应用程序进行大规模重组,需要进行大量测试,要么如果可以在 CPU 绑定操作的同时进行 API 调用,那么我将保持原样。

总而言之,这是不好的做法,还是可以在同一任务中进行 CPU 密集型工作和 API 调用?该任务正在处理一条 JSON 消息。

Ste*_*ary 5

我读过的所有内容都说使用await task.run进行cpu绑定操作。并使用await async进行http外部调用

一般准则是使用async/await作为 I/O。如果您需要从 UI 线程中卸载Task.RunCPU 密集型操作,则该操作很有用。例如,在 ASP.NET 等服务器场景中,您不希望使用CPU 密集型代码。这是因为 ASP.NET已经将您的代码安排在单独的线程池线程上。Task.Run

在您的例子中,您有一个控制台应用程序,它没有 UI 线程。但它也没有 ASP.NET 提供的自动调度到线程池线程的功能。

如果可以与 cpu 绑定操作一起进行 api 调用,那么我将保持原样。

无论哪种方式都很好。由于代码正在awaiting Task.Run,因此在另一个线程池线程上的操作完成之前,它不会继续(大概是处理下一条消息)。所以,这Task.Run并没有多大帮助,但也没有太大伤害。

如果您需要更高的性能(具体来说,同时处理消息),那么您应该研究诸如 TPL Dataflow 或 System.Threading.Channels 之类的东西,它们允许您用Task.Run可以并行运行的工作队列替换它们。这将为您提供更像 ASP.NET 提供的开箱即用的东西。