用于子计算的缓存数组导致Parallel.For / Foreach

时间:2016-07-23 17:52:27

标签: c# .net performance parallel.foreach

我有一个方法可以计算每次迭代中的一些数组,然后对它们求和(按索引方式添加每个数组)并返回总和数组。

我正在寻找一种高效的并行方法。本质上,我想避免不断创建数组并重新使用它们。

示例:

private void Computation(float[] result)
{
  var _lock = new object();
  Parallel.For(0, 50, x =>
  {
    var subResult = new float[200*1000];
    CalculateSubResult(subResult);

    lock(_lock)
       for (int i = 0; i < subResult.Length; i++)
          result[i] += subResult[i];


  });
}

问题是这些Parallel.For's是嵌套的(因为CalculateSubResult也做类似的循环)。这导致不断创建和丢弃用于保存子计算结果的数组。

要解决此问题,我使用ThreadLocal来存储缓存的数组:

ThreadLocal<float[]> threadLocalArray = new ThreadLocal<float[]>(()=>new float[200*1000]);

private void ComputationWithThreadLocal(float[] result)
{
  var _lock = new object();
  Parallel.For(0, 50, x =>
  {
    var subResult = threadLocalArray.Value;
    CalculateSubResult(subResult);

    lock (_lock)
      for (int i = 0; i < subResult.Length; i++)
        result[i] += subResult[i];

     Array.Clear(subResult,0,subResult.Length);
  });
}

这种方法存在两个问题:

  1. 随着时间的推移(这是长时间运行计算的一部分)threadLocalArray存储越来越多的数组,即使只有很少的逻辑核心,也会导致内存泄漏。在计算完成之前我无法调用threadLocalArray.Dispose(),因此无法阻止它的增长。

  2. 总结子计算结果需要锁定并且浪费。我希望有一个本地的每线程总和,并且只有在线程完成其分区工作后,才会发生求和。

  3. 有一种处理2的重载方法。

    public static ParallelLoopResult For<TLocal>(
        int fromInclusive,
        int toExclusive,
        Func<TLocal> localInit,
        Func<int, ParallelLoopState, TLocal, TLocal> body,
        Action<TLocal> localFinally
    )
    

    Func<TLocal> localInit只会初始化一个subResult数组:()=>new float[200*1000]。在这种情况下,Action<TLocal> localFinally每个分区只执行一个,这样更有效。但问题是localInit不能使用()=>threadLocalArray.Value来获取线程局部数组,因为如果Parallel.For循环是递归嵌套的,那么同一个数组用于不同嵌套级别的子计算,导致不正确的结果

    我想我正在寻找类似的东西(CachedArrayProvider是一个需要管理重用数组的类):

    Parallel.For(0,50, 
      ()=>CachedArrayProvider.GetArray(), 
      (i, localArray) => {/*body*/},
      (localArray) =>
      {
        //do final sum here
        CachedArrayProvider.ReturnArray(localArray);
      }
    );
    

    有什么想法吗?

0 个答案:

没有答案