在外部任务中WaitAll vs WhenAll.Result

时间:2015-01-07 11:47:25

标签: c# .net asynchronous task-parallel-library

这是我之前question的延续。 看一下下面的代码示例:

    private static Task<List<int>>[] Tasks
    {
        get 
        { 
            return Enumerable.Range(1, 1000).Select(n => Task.Run(() => Compute(n)))
                             .ToArray(); //enumerate immediately to run the tasks...
        }
    }

    public static void Test()
    {
        var baseTasks = new Task[100];
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < 100; i++)
        {
            baseTasks[i] = Task.Run(() =>
            {
                var tasks = Tasks;

                // IMPORTANT: here we could call:                    
                // Task.WaitAll(tasks);
                // and the result would be the same...

                tasks.Select(t => t.Result).SelectMany(r => r).ToList();
            });

        }
        Task.WaitAll(baseTasks);
        Console.WriteLine("Select - {0}", stopwatch.Elapsed);

        baseTasks = new Task[100];
        stopwatch.Restart();
        for (int i = 0; i < 100; i++)
        {
            baseTasks[i] = Task.Run(() =>
            {
                Task.WhenAll(Tasks).Result.SelectMany(result => result).ToList();
            });

        }
        Task.WaitAll(baseTasks);
        Console.WriteLine("Task.WhenAll - {0}", stopwatch.Elapsed);
    }

如果你运行这个,你会看到WhenAll这里的表现要差得多。那是为什么?

为什么我要问这个?我认为写这样的代码是正常的:

for (int i = 0; i < x; i++) 
{
    Task.Run(() => 
    {
        Task<Res>[] tasks = CreateBunchOfTasks();
        Res[] results = FetchResults(tasks);
        //do something with results...
    });
}

然后您可能想知道,从多个任务中获取结果的最佳方法是什么。看起来这里最好的方式是:

tasks.Select(t => t.Result).SelectMany(r => r) 

WhenAll是我们应该避免的......

请注意,如果我要移除外部任务,那么WhenAll并枚举Result属性(或WaitAll,其行为相同)给出非常相似的表现:

for (int i = 0; i < x; i++) 
{
    Task<Res>[] tasks = CreateBunchOfTasks();
    Res[] results = FetchResults(tasks);
    //do something with results...
}

0 个答案:

没有答案