使用C#以并行方式将集合分成相等的批次

时间:2019-01-16 09:34:14

标签: c# performance

我正在尝试将集合分成相等数量的批次。下面是代码。

   public static List<List<T>> SplitIntoBatches<T>(List<T> collection, int size)
    {
        var chunks = new List<List<T>>();
        var count = 0;
        var temp = new List<T>();

        foreach (var element in collection)
        {
            if (count++ == size)
            {
                chunks.Add(temp);
                temp = new List<T>();
                count = 1;
            }
            temp.Add(element);
        }

        chunks.Add(temp);

        return chunks;
    }

我们可以使用Parallel.ForEach()来获得更好的性能吗,因为列表中有大约100万个项目?

谢谢!

1 个答案:

答案 0 :(得分:3)

如果要关注性能,我的想法(以影响的顺序递增):

    在创建列表时
  • 调整列表大小会节省很多的工作,即在开始复制之前 找出输出批处理的大小,即{{1} }
  • 使用数组比使用列表更有效-temp = new List<T>(thisChunkSize)
  • 尤其是如果您使用new T[thisChunkSize](或内部使用的BlockCopy,而不是一个个地复制单个元素
  • 一旦您已计算出每个块的偏移量,则各个块副本可能会并行执行,但我不认为这样做会更快-内存带宽将成为此时的限制因素< / li>
  • 但是最终修复是:完全不复制数据,而只是在现有数据上创建 ranges ;例如,如果使用数组,CopyTo会有所帮助;如果您愿意使用新的.NET功能,则非常适合ArraySegment<T> / Memory<T>-在现有阵列上创建内存/跨度范围基本上是免费且即时的-即,使用{{ 1}},然后返回Span<T>或类似值。

即使您无法切换到T[] / List<Memory<T>>等,也会返回仍可以使用的类似 的内容-即ArraySegment<T>其中{{1 }}类似于:

Memory<T>

并通过适当处理List<ListSegment<T>>ListSegment<T>使代码与readonly struct ListSegment<T> { // like ArraySegment<T>, but for List<T> public List<T> List {get;} public int Offset {get;} public int Count {get;} } 一起使用。