这是我之前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...
}