重构异步/等待并行处理

时间:2016-04-06 01:03:58

标签: c# asynchronous parallel-processing async-await task

仍在使用C#进行学习阶段并遇到了一个我需要帮助的问题。考虑以下代码:

private async Task<String> PrintTask()
{
    await Task.Delay(3000);
    return "Hello";
}

private async void SayHelloTwice()
{
    string firstHello = await PrintTask();
    string secondHello = await PrintTask();

    Console.WriteLine(firstHello);
    Console.WriteLine(secondHello);
}

现在SayHelloTwice()需要6秒才能完成。但是,我希望检索任务并行运行,因此只需3秒即可完成。我将如何重构我的代码来实现这一目标?谢谢!

3 个答案:

答案 0 :(得分:4)

执行此操作的正确方法(没有死锁风险)是使用Task.WhenAll

private async void SayHelloTwice()
{
    string[] results = await Task.WhenAll(
        PrintTask(),
        PrintTask());

    Console.WriteLine(results[0]);
    Console.WriteLine(results[1]);
}

图书馆作家经常会努力做出回调&#34;任务中的代码在调用它的原始线程上运行。这通常是因为只能从单个线程访问对象。

使用Task.ResultTask.WaitAll之类的阻止调用时,线程暂停(无法执行其他工作),直到Task完成。

但是如前所述,Task通常会等待调用线程释放,因此可以用它来完成任务。

所以,在第一种情况下,outter&#34; Task&#34;持有线程,等待完成。

第二种情况,内部&#34;任务&#34;正在等待线程完成。

Ergo将永远不会完成。

答案 1 :(得分:3)

一般来说,你想要的是开始这两项任务,然后等待。 一种直截了当的方式是:

private async void SayHelloTwice()
{
    // Start the tasks, don't wait
    Task<string> firstHello = PrintTask();
    Task<string> secondHello = PrintTask();

    // Wait for results
    string firstResult = await firstHello;
    string secondResult = await secondHello;

    // Print results
    Console.WriteLine(firstResult);
    Console.WriteLine(secondResult);
}

这里发生的是调用PrintTask()将开始执行该方法,一旦执行到达执行实际异步操作的第一个await,将返回正在运行的任务并将其分配给firstHello 。 第二个问题也是如此。 然后等待两者完成并打印结果。

此实现只是简化工作方式的一个示例。在实际代码中,您应该使用Task.WhenAll等待所有正在运行的任务

答案 2 :(得分:3)

  • 您可以使用Task.WhenAll等待多项任务。
  • 您还应该更喜欢返回Task而不是voidasync/await - when to return a Task vs void?):

    private static async Task SayHelloTwice()
    {
        var hellos = await Task.WhenAll(PrintTask(), PrintTask());
        Console.WriteLine(hellos[0]);
        Console.WriteLine(hellos[1]);
    }