代码之家  ›  专栏  ›  技术社区  ›  gknauth

使用parallel.foreach在最小值中选择最小值

  •  6
  • gknauth  · 技术社区  · 15 年前

    我对C是新的, Parallel.ForEach 和.NET。我想将涉及数千个地点的搜索并行化。对于每个位置,我计算大圆距离。这是一个我想要扩展到不同核心的计算。我的问题是如果我只有 线程局部变量,如 MSDN TPL example ?结果,我看了一下 Interlocked 看到了它的选择 Add , CompareExchange , Decrement , Exchange , Increment Read ,但我不只是增加、增加、减少或测试相等性。我想返回对象,通过几个线程并行运行,其中有最短的 总体的 距离。我的直觉说这应该很容易,我应该能够创造出一些小物体来包裹 Location 还有一段距离,但是我如何从每一条线中捕捉到最好的答案 然后 选择其中最短的距离?以下是非并行版本:

    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 .

    1 回复  |  直到 15 年前
        1
  •  11
  •   Reed Copsey    15 年前

    这里最简单的选择是切换到plinq:

    Location findClosestLocation(Location myLocation, List<Location> allLocations)
    {
         return allLocations
                   .AsParallel()
                   .Min(location => greatCircle(myLocation, location));
    }
    

    也就是说,这基本上只是 aggregation with parallel constructs . 如果你想坚持使用并行类,你有几个选择。一个选项是使用锁定在块中自己同步这个文件。我不建议这样做,因为这会影响你的整体表现。

    更好的选择是使用 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 . 这基本上将操作更改为每个线程一个锁操作,而不是每个处理元素一个锁,因此您比简单的锁解决方案获得更高的吞吐量。

    推荐文章