如何使用PLINQ处理数组的块

时间:2012-07-13 09:42:49

标签: .net linq c#-4.0 parallel-processing plinq

我需要使用大量的双精度数,并使用处理器密集型函数以块的形式处理它。

我原来的阵列非常大,大约有200MB的信号数据。

我需要将它们分成5000个双打,使用一个返回单个double的函数来处理那些具有处理器密集度的数学。需要每个函数结果来创建稍后使用的有序数组。

认为这对于使用PLINQ的并行性来说是最佳的,但我不太清楚如何去做。

我写的天真实现看起来像这样:

        var processedList = new List<double>();

        var chunk = new List<double>;
        foreach (var rawSample in drop.RawSamples)
        {
            chunk.Add(rawSample);

            if (chunk.Count == 5000)
            {
                // Do long processing here
                processedList.Add(LongProcessingFunction(chunk));

                chunk.Clear();
            }
        }

        // Do something later with the list of processed values.....

那么,我从哪里开始使用PLINQ?我需要能够使用处理器的所有核心来执行长时间的密集功能。

我看到IEnumerable有一个Take(n)函数.....我可以使用它吗?

我可以在这里使用AsParallel吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

首先,如果你正在处理这些数据,你应该避免逐个元素地处理它,如果可以的话。在您的代码中,您可以通过以5000为增量迭代整数并使用Array.Copy()之类的东西来实现。

或者更好的是,根本不做任何复制,让LongProcessingFunction接受一个数组(或IList<T>IReadOnlyList<T>,如果你在.Net 4.5;但是使用接口确实有一些开销)和该数组的偏移量。

如果您想要使代码平行,可以将ParallelEnumerable.Range()AsOrdered()一起使用(这需要以正确的顺序生成结果)和Select()

double[] result = ParallelEnumerable.Range(0, drop.RawSamples.Length / chunkSize)
    .AsOrdered()
    .Select(i => LongProcessingFunction(drop.RawSamples, i * chunkSize))
    .ToArray();

答案 1 :(得分:0)

我建议在索引源上实现一个分区程序,它会将你的源分成5000个元素的块。然后可以使用AsParallel对它们中的每一个进行处理。

class Program
{
    static void Main(string[] args)
    {

        IList<double> rawData =  [Your raw data here];

        IList<double> result =
            rawData
                .Partition(5000)
                .AsParallel()
                .AsOrdered()
                .Select(chunk => LongProcessingFunction(chunk))
                .ToList();
    }

    private static double LongProcessingFunction(IList<double> chunk)
    {
        throw new NotImplementedException();
    }
}

public static class MyExtensions
{
    public static IEnumerable<List<T>> Partition<T>(this IList<T> source, Int32 size)
    {
        for (int i = 0; i < Math.Ceiling(source.Count / (Double)size); i++)
        {
            yield return new List<T>(source.Skip(size*i).Take(size));
        }
    }
}