如何最好地并行运行两个异步任务并等待两者的返回结果?

Cha*_*adD 0 c# asynchronous async-await

我正在寻找满足以下要求的模式的简单 C# 示例:

  1. 我想异步执行 2 个方法,在不等待第一个完成的情况下启动第二个方法。
  2. 每个方法都接受一个参数并返回和输出值。
  3. 然后我想在继续之前等待两者的结果。

这似乎是我可以轻松使用 async 和 await 关键字的场景,但是在查看了几个 Hello World 示例后,我很惊讶我无法轻松地同时满足上述所有条件。例如,虽然使用 await 关键字使我的 UI 不会阻塞并允许我的应用程序在我等待方法完成时继续响应事件,但这些方法仍在同步执行。或者,如果我能够异步执行,我在尝试将输入参数传递给调用方法并接收返回结果时遇到了麻烦。

以下内容似乎符合我的要求,并让我相信我可以充分利用它,但首先我想得到您关于如何改进它的反馈。

我之前玩过 Threads 并发现它使我的代码变得更加复杂,并期望“async 和 await”关键字会让我的生活更轻松,但以下似乎满足我要求的代码甚至没有使用这些关键字。我在这里使用“并行任务库”吗?如果是这样,您将如何将此库中的功能与 async 和 await 功能进行对比?

using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ASyncCourse
{
    static class Program
    {
        static void Main()
        {
            int result1 = 0;
            int result2 = 0;

            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            Task task1 = Task.Run(() => result1 = DoSomeWork(1));
            Debug.WriteLine($"After Task1: {stopWatch.Elapsed}");

            Task task2 = Task.Run(() => result2 = DoSomeOtherWork(10));
            Debug.WriteLine($"After Task2: {stopWatch.Elapsed}");

            Task.WaitAll(task1, task2);
            stopWatch.Stop();

            int sum;
            
            sum = result1 + result2; 
            Debug.WriteLine($"Sum: {sum}");
            Debug.WriteLine($"Final: {stopWatch.Elapsed}");
        }

        private static int DoSomeOtherWork(int waitFor)
        {
            Thread.Sleep(waitFor * 1000);
            return waitFor;
        }

        private static int DoSomeWork(int waitFor)
        {
            Thread.Sleep(waitFor * 1000);
            return waitFor;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

AAA*_*ddd 5

您可以使用异步并等待模式awaitCPU密集型任务,然而,你将需要使用async Task Main()切入点

public static async Task Main()
{
    var task1 = Task.Run(() => CpuWork1(1));
    var task2 = Task.Run(() => CpuWork2(10));
    
    var result1 = await task1;
    var result2 = await task2;

    // or

    var results = await Task.WhenAll(task1, task2) ;
}
Run Code Online (Sandbox Code Playgroud)

如果您的工作负载 IO 绑定的,那么它们将具有async Task<T>签名,并且您将只返回任务await的方法,类似于上面的(而不是使用)Task.Run

完整示例

static async Task Main()
{

   var stopWatch = new Stopwatch();
   stopWatch.Start();

   var task1 = Task.Run(() =>  DoSomeWork(1));
   var task2 = Task.Run(() =>  DoSomeOtherWork(10));

   var results = await Task.WhenAll(task1, task2);
   stopWatch.Stop();

   Debug.WriteLine($"Sum: {results.Sum()}");
   Debug.WriteLine($"Final: {stopWatch.Elapsed}");
}
Run Code Online (Sandbox Code Playgroud)

或者类似的异步方法

static async Task Main()
{

   var stopWatch = new Stopwatch();
   stopWatch.Start();

   var task1 = DoSomeWorkAsync(1);
   var task2 = DoSomeOtherWorkAsync(10);

   var results = await Task.WhenAll(task1, task2);
   stopWatch.Stop();

   Debug.WriteLine($"Sum: {results.Sum()}");
   Debug.WriteLine($"Final: {stopWatch.Elapsed}");
}

private static async Task<int> DoSomeOtherWorkAsync(int waitFor)
{
   // some IO bound workload
   await Task.Delay(waitFor * 1000);
   return waitFor;
}

private static async Task<int> DoSomeWorkAsync(int waitFor)
{
   // some IO bound workload
   await Task.Delay(waitFor * 1000);
   return waitFor;
}
Run Code Online (Sandbox Code Playgroud)