我想知道为什么花这么长时间才能从已经完成的任务中获得结果。
List<Task<T>> myTasks = someList.Select(x => Task.Run(() => DoSomethingWith(x)));
Task.WaitAll(myTasks.ToArray());
var myResults = myTasks.Select(task => task.Result); // the line that takes too long
对这些单独的行进行计时表明,在最后一行中花费了大量时间(10个任务超过25ms)。在我看来,获得结果应该几乎是瞬时的,因为那时结果应该已经存在。在这种情况下是否有更好的方法来获得结果?
答案 0 :(得分:4)
我会在您更新问题时进行更新,但这是我的最佳猜测。
此行无法编译,因为Select不会返回列表:
List<Task<T>> myTasks = someList.Select(x => Task.Run(() => DoSomethingWith(x)));
我要冒昧地猜测您实际上是在这样做:
var myTasks = someList.Select(x => Task.Run(() => DoSomethingWith(x)));
...会产生冷IEnumerable
:只会在实际迭代结束时运行。
在上面的代码中,您在调用.ToArray()
时对其进行迭代。但是,您描述为耗时25ms的那行同样只会产生另一个冷IEnumerable<>
。这里没有任何实际的工作:
var myResults = myTasks.Select(task => task.Result);
所以我再次冒昧地猜测您正在做更多这样的事情:
var myResults = myTasks.Select(task => task.Result).ToList();
...将在myTasks
上进行第二次迭代, ,导致Task.Run(...)
再次被someList
中的每个项目调用,然后等待所有这些任务完成。
换句话说,您要做两次工作,最后一次在您引用的行中进行一次。
幸运的是,使用任务并行库有更好的方法来完成您的工作。
var myResults = someList
.AsParallel()
.Select(x => DoSomethingWith(x))
.ToList();
答案 1 :(得分:-1)
如果您确定第三行是导致速度下降的那一行,那么就没什么可做的了。这就是所有运行时库代码,并且在进行优化时,MS运行得非常紧密。
您可能希望手动遍历myTasks以避免选择代码,但是如果您花了几毫秒的时间,我会感到惊讶。