基本上这就是问题,我有一个函数“GetAllCandidates”接受一个列表,计算一些东西,改变参数并使用Task.Factory.StartNew调用自己来计算原始数组不同变形的所有可能输出。 / p>
private void GetAllCandidates(List<int> values)
{
Interlocked.Increment(ref _count);
for (var i = values.Count - 1; i >= 1; i --)
{
//Do work and calculations
Task.Factory.StartNew(
() => GetAllCandidatePowers(newPowers)
);
}
}
我需要充分利用CPU上的内核并等待所有任务完成,这就是问题所在。
有关如何处理此类问题的任何提示?
答案 0 :(得分:4)
您可以使用Task.WhenAll
方法(在.NET 4.5中引入)在递归的每一步解开并行性:
private Task GetAllCandidates(List<int> values)
{
Interlocked.Increment(ref _count);
List<Task> tasks = new List<Task>();
for (var i = values.Count - 1; i >= 1; i--)
{
//Do work and calculations
Task task = Task.Factory.StartNew(() => GetAllCandidatePowers(newPowers));
tasks.Add(task);
}
return Task.WhenAll(tasks);
}
这样,您只需等待应用程序中GetAllCandidates
方法的最外层调用(如果有的话),只阻塞一个线程。
编辑:使用LINQ等效制定for
循环:
private Task GetAllCandidates(List<int> values)
{
Interlocked.Increment(ref _count);
var tasks = Enumerable.Range(1, values.Count - 1).Reverse().Select(i =>
{
//Do work and calculations
return Task.Factory.StartNew(() => GetAllCandidatePowers(newPowers));
});
return Task.WhenAll(tasks);
}
答案 1 :(得分:2)
让GetAllCandidates
保持一个函数本地的任务列表。在函数结束时等待它们。只要您启动多个任务,这仍然可以提供并行性。
答案 2 :(得分:1)
听起来你的目标是提高整个过程的表现。假设执行for循环的顺序并不重要,可以使用TPL。我认为它会让你获得更快的结果。
private void GetAllCandidates(List<int> values)
{
Interlocked.Increment(ref _count);
Parallel.ForEach(test, item =>
{
//Do work and calculations
var t = new Task().Run(GetAllCandidatePowers(newPowers));
// Although if you are waiting here, you might as well just run it synchronously.
t.Wait();
);
}
}
更新:Use PLINQ以维持订单
我提供了一个使用PLINQ并行运行操作然后以原始顺序返回结果集的示例。除非这些操作很昂贵,或者存在大量操作,否则您可能不会发现性能大幅提升。如果你正在做一些沉重的工作,或者有大量的物品要经过,那么这应该会帮助你。
private void GetAllCandidates(List<int> values)
{
Interlocked.Increment(ref _count);
values.AsParallel().AsOrdered().ForAll((item) =>
{
// Do stuff
GetAllCandidates(newPowers);
}
}