我是C#,Parallel.ForEach和.NET的新手.我想并行化涉及数千个位置的搜索.对于每个位置,我计算大圆距离.这是我想要传播到不同核心的计算.我的问题是如果我只有一个线程局部变量,如何在这个
MSDN TPL example中如何做到这一点?结果,我查看了Interlocked,并看到了它的选项Add,CompareExchange,Decrement,Exchange,Increment和Read,但我不只是添加,递增,递减或测试相等性.我希望通过并行运行的多个线程返回对象,该对象具有最短的总距离.我的直觉说这应该很容易,我应该能够创建一个包含位置和距离的小对象,但是我如何从每个线程中捕获最佳答案然后选择它们之间的最短距离?这是非并行版本:
Location findClosestLocation(Location myLocation,List<Location> allLocations) { double closest = double.MaxValue; Location closestLoc = null; foreach (Location aLoc in allLocations) { if (aLoc != myLocation) { double d = greatCircle(myLocation,aLoc); if (d < closest) { closest = d; closestLoc = aLoc; } } } return closestLoc; }
我确实看到DDJ Blog Post似乎提供了很好的建议,但我想知道这是否是最好的建议.我看到作者循环遍历数组,并想知道是否没有更多功能的方法来做到这一点.在功能世界中,我会使用map,lambda和min.
解决方法
这里最简单的选择是切换到PLINQ:
Location findClosestLocation(Location myLocation,List<Location> allLocations) { return allLocations .AsParallel() .Min(location => greatCircle(myLocation,location)); }
话虽如此,这基本上只是aggregation with parallel constructs.如果你想坚持Parallel类,你有几个选择.一种选择是使用锁定在块内自己同步.我不推荐这个,因为它会损害你的整体表现.
更好的选择是使用提供本地状态的Parallel.ForEach方法.他们会允许你重写为:
Location findClosestLocation(Location myLocation,List<Location> allLocations) { double closest = double.MaxValue; Location closestLoc = null; object sync = new object(); Parallel.ForEach<Location,Tuple<double,Location>( allLocations,() => new Tuple(double.MaxValue,null),(location,loopState,localState) => { double d = greatCircle(myLocation,aLoc); if (d < localState.Item1) return new Tuple(d,aLoc); else return localState; },localState => { lock(sync) { if (localState.Item1 < closest) { closest = localState.Item1; closestLoc = localState.Item2; } } } ); return closestLoc; }
我使用local state for aggregations in detail on my blog覆盖.这基本上将操作更改为每个线程一个锁定操作,而不是每个处理元素一个锁定,因此您获得比天真锁定解决方案更高的吞吐量.