[英]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.