C# Task.WaitAll()和execute Task.Wait之间的性能差距问题。请按顺序等待

C# Task.WaitAll()和execute Task.Wait之间的性能差距问题。请按顺序等待,c#,multithreading,asynchronous,concurrency,task,C#,Multithreading,Asynchronous,Concurrency,Task,我想将并发性添加到一些同步代码中,并在过程中发现了一个难以理解的性能问题 下面代码的运行结果是: Mission Fibonacci1Async cost 9.4195388 seconds, value 75025 Mission Fibonacci2Async cost 0.2260129 seconds, value 75025 唯一不同的是2rd函数添加了一行wait Task.WhenAll(newtask[]{t1,t2}),使性能提高40倍 谁能给我解释一下吗 stati

我想将并发性添加到一些同步代码中,并在过程中发现了一个难以理解的性能问题

下面代码的运行结果是:

Mission Fibonacci1Async cost 9.4195388 seconds, value 75025
Mission Fibonacci2Async cost 0.2260129 seconds, value 75025
唯一不同的是2rd函数添加了一行wait Task.WhenAll(newtask[]{t1,t2}),使性能提高40倍

谁能给我解释一下吗

    static Task<int> Fibonacci1Async(int n)
    {
        return Task.Run<int>(() => Fibonacci1(n));
    }

    static int Fibonacci1(int n)
    {
        if (n == 0) return 0;
        else if (n == 1) return 1;
        else
        {
            var t1 = Fibonacci1Async(n - 1);
            var t2 = Fibonacci1Async(n - 2);
            return t1.Result + t2.Result;
        }
    }

    static Task<int> Fibonacci2Async(int n)
    {
        return Task.Run<int>(() => Fibonacci2(n));
    }

    static int Fibonacci2(int n)
    {
        if (n == 0) return 0;
        else if (n == 1) return 1;
        else
        {
            var t1 = Fibonacci2Async(n - 1);
            var t2 = Fibonacci2Async(n - 2);

            Task.WaitAll(new Task[] { t1, t2 });
            return t1.Result + t2.Result;
        }
    }

    static void Benchmark(Func<int, Task<int>> func)
    {
        DateTime time = DateTime.Now;
        var task = func(25);
        task.Wait();
        TimeSpan cost = DateTime.Now - time;
        Console.WriteLine("Mission {0} cost {1} seconds value {2}", func.Method.Name, cost.TotalSeconds, task.Result);
    }

    static void Main(string[] args)
    {
        Benchmark(Fibonacci1Async);
        Benchmark(Fibonacci2Async);
        Console.ReadKey();
        return;
    }
静态任务Fibonacci1Async(int n)
{
返回任务。运行(()=>Fibonacci1(n));
}
静态int Fibonacci1(int n)
{
如果(n==0)返回0;
如果(n==1),则返回1;
其他的
{
var t1=Fibonacci1Async(n-1);
var t2=Fibonacci1Async(n-2);
返回t1.Result+t2.Result;
}
}
静态任务Fibonacci2Async(int n)
{
返回任务。运行(()=>Fibonacci2(n));
}
静态int Fibonacci2(int n)
{
如果(n==0)返回0;
如果(n==1),则返回1;
其他的
{
var t1=Fibonacci2Async(n-1);
var t2=Fibonacci2Async(n-2);
Task.WaitAll(新任务[]{t1,t2});
返回t1.Result+t2.Result;
}
}
静态无效基准(Func Func)
{
DateTime=DateTime.Now;
var任务=func(25);
task.Wait();
TimeSpan成本=日期时间。现在-时间;
WriteLine(“任务{0}成本{1}秒值{2}”、func.Method.Name、cost.TotalSeconds、task.Result);
}
静态void Main(字符串[]参数)
{
基准(Fibonacci1Async);
基准(Fibonacci2Async);
Console.ReadKey();
返回;
}

我怀疑答案与此有关

在表达式
t1.Result+t2.Result
中,
+
运算符从左到右(串行)计算其参数。因此它将在
t1
上阻塞,然后在
t2
上阻塞

我猜在您的系统上,大部分时间
t1
已经启动,但不是
t2
。在这种情况下,
Task.WaitAll
可以将
t2
内联到当前线程池任务中,而不是启动新的线程池任务,但是
+
将在
t1
上阻塞

这只是一个猜测;你应该使用一个剖析器来找出到底发生了什么

我无法在我的系统上复制这个。我总是看到这两个版本大致相同,即使将处理器关联应用于流程


另外,命名约定
Async
在这里并不适用。此代码没有使用
async
/
await
-它使用的是任务并行库。

命名约定与await/async无关。这是一个实现细节。它指定调用者接收任务并获取非阻塞行为。后缀
Async
与返回类型组合表示该方法使用基于任务的异步模式。我想您可以假设这些
*Async
方法是TAP,但它们肯定不是TAP实现的好例子。例如,FileStream.ReadAsync不在内部使用wait。它使用IO完成端口。没什么问题。调用方不需要知道。
FileStream.ReadAsync
也不在本质上同步的代码周围实现
Task
包装器。