C# 保留顺序时的Parallel.ForEach

C# 保留顺序时的Parallel.ForEach,c#,collections,asynchronous,concurrency,parallel-processing,C#,Collections,Asynchronous,Concurrency,Parallel Processing,我有一个列表,我喜欢将每个字节[]反序列化为Foo。列表是有序的,我喜欢编写一个并行循环,在这个循环中,生成的List以与原始byte[]相同的顺序包含所有Foo。这个列表非常大,使并行操作变得值得。是否有一种内在的方法来实现这一点 如果没有,有什么办法可以在同步运行的基础上实现加速 谢谢您可以使用带有索引int键的线程安全字典来存储来自foo的reult 因此,在最后,您将拥有字典中的所有数据排序器。根据您提供的信息,我知道您希望有一个大小等于字节输入数组的Foo输出数组?这是正确的吗 如果是

我有一个
列表
,我喜欢将每个
字节[]
反序列化为Foo。列表是有序的,我喜欢编写一个并行循环,在这个循环中,生成的
List
以与原始
byte[]
相同的顺序包含所有Foo。这个列表非常大,使并行操作变得值得。是否有一种内在的方法来实现这一点

如果没有,有什么办法可以在同步运行的基础上实现加速


谢谢

您可以使用带有索引int键的线程安全字典来存储来自foo的reult
因此,在最后,您将拥有字典中的所有数据排序器。根据您提供的信息,我知道您希望有一个大小等于字节输入数组的Foo输出数组?这是正确的吗

如果是,则操作简单。不要为锁定或同步构造而烦恼,它们会侵蚀并行化带来的所有速度

相反,如果您遵守这一简单规则,任何算法都可以并行化,而无需锁定或同步:

对于处理的每个输入元素X[i],可以从任何输入元素X[j]读取,但只能写入输出元素Y[i]

查找散布/聚集,这种类型的操作称为聚集,因为只有一个输出元素被写入

如果您可以使用上述原则,那么您需要预先创建输出数组Foo[],并在输入数组上使用Parallel.For not ForEach

例如

List inputArray=new List();
int[]outputArray=新的int[inputArray.Count];
var waitHandle=新手动重置事件(错误);
int计数器=0;
对于(0,inputArray.Count,索引=>
{
//将索引传递给for循环,执行长时间运行操作
//关于输入项
//仅写入单个输出项
输出阵列[索引]=数据操作(输入阵列[索引]);
if(联锁增量(参考计数器)=输入阵列计数-1)
{
waitHandle.Set();
}
});
waitHandler.WaitOne();
//如果需要,可选择转换回列表
var outputList=outputArray.ToList();

请发布一些示例代码,对于记录来说,并行并不一定会使速度更快、效率更高。。。不知道Parallel.For是否能解决您的问题。这是与此重复的:因此,您可以使用PLINQ(AsOrdered,AsParallel)为了完成任务。最好使用与
Select
Map
相当的并行方法来保留输入顺序。@adt:您给出的答案是:
parallel。For
解决了这个问题。将此作为答案发布。我将投+1票。@adt,如果我有代码,我就不需要问;-)我可以添加一个简单的for循环,如果这对您有帮助的话?谢谢,我知道这一点,但听起来非常复杂。我基本上需要另一个完整的过程来等待下一个传入的Foo,检查同步性,并以正确的顺序将项目添加到结果列表中。看起来相当大的开销可能会破坏并行运行的整个概念。将您的答案标记为所需的解决方案,尽管最后我在svick的帮助下使用了自定义的IPropagatorBlock和TPLDataflow。虽然这个问题和数据流表面上看起来是两个截然不同的概念,但IPropagatorBlock中数据块的并行处理在我的具体问题上远远优于任何并行的.For循环。我发现映射和完成通知的同步开销非常昂贵,而且TPL数据流针对的是像我这样的场景。但这丝毫不影响您对我的具体问题的解决……其中不包括同步和完成通知问题。这是关于平行的。Foreach在保持秩序的同时,你提出的解决方案符合要求。非常感谢。说得好!任务并行库是一种优越的解决方案。不过,我很惊讶它的表现比我好。可能是它限制了任务,使每个线程执行多个序列化?对于以上内容,您可以使用整数计数器和
联锁的完整通知。增量(ref counter)
来测试是否已处理所有元素。然后设置waithandle以继续。
        List<byte[]> inputArray = new List<byte[]>();
        int[] outputArray = new int[inputArray.Count];

        var waitHandle = new ManualResetEvent(false);
        int counter = 0;

        Parallel.For(0, inputArray.Count, index =>
            {
                // Pass index to for loop, do long running operation 
                // on input items
                // writing to only a single output item
                outputArray[index] = DoOperation(inputArray[index]);

                if(Interlocked.Increment(ref counter) == inputArray.Count -1)
                {
                    waitHandle.Set();
                }
            });

        waitHandler.WaitOne();

        // Optional conversion back to list if you wanted this
        var outputList = outputArray.ToList();