简体   繁体   English

C# 并行映射迭代器保留顺序

[英]C# parallel mapping iterator retaining order

I have an Enumerator<T> as input, a mapping function that converts a T to an S , and I want to deliver an Enumerator<S> containing the results of the mapping.我有一个Enumerator<T>作为输入,一个将T转换为S的映射函数,我想提供一个包含映射结果的Enumerator<S> The mapping function is potentially expensive (for example, it might parse a 1Mb XML document) so I want to process multiple items in parallel;映射函数可能很昂贵(例如,它可能会解析一个 1Mb 的 XML 文档),所以我想并行处理多个项目; but I want the output Enumerator<S> to retain order.但我希望输出Enumerator<S>保留顺序。 This means there will have to be some buffering;这意味着必须有一些缓冲; but I don't want to retain the whole sequence in memory.但我不想将整个序列保留在内存中。

I currently have this working using a Parallel.ForEach() and a ChannelWriter/ChannelReader pair: the callback in the ForEach applies the mapping function and writes the result to the ChannelWriter , and the result Enumerator reads the items using the ChannelReader .我目前使用Parallel.ForEach()ChannelWriter/ChannelReader对进行此工作: ForEach中的回调应用映射函数并将结果ChannelWriter ,结果Enumerator使用ChannelReader读取项目。 The only problem is that this doesn't retain order (mapped items are delivered in the order they become available, which is different from the input order).唯一的问题是这不保留顺序(映射的项目按照它们可用的顺序交付,这与输入顺序不同)。

I get the impression that there's a role here for an OrderablePartitioner , but I'm having great difficulty finding any usable information on how to use this class.我的印象是这里有一个OrderablePartitioner的角色,但我很难找到有关如何使用此类的任何可用信息。

The simplest solution is probably the PLINQ library.最简单的解决方案可能是PLINQ库。 The Select operator does the mapping, the AsOrdered ensures the preservation of order, and a couple of options regarding buffering ensures that the PLINQ buffers as little as possible: Select运算符进行映射, AsOrdered确保顺序的保存,以及一些关于缓冲的选项确保 PLINQ 缓冲区尽可能少:

public static IEnumerable<TResult> Map<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, TResult> mapping,
    int degreeOfParallelism)
{
    return Partitioner
        .Create(source, EnumerablePartitionerOptions.NoBuffering)
        .AsParallel()
        .AsOrdered()
        .WithDegreeOfParallelism(degreeOfParallelism)
        .WithMergeOptions(ParallelMergeOptions.NotBuffered)
        .Select(mapping);
}

In case you wish to chain the Map method multiple times consecutively in a pattern of a pipeline, see this answer.如果您希望以管道模式连续多次链接Map方法,请参阅答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM