quoteBuffer = new TransformBlock<Tuple<Symbol, int>, List<Quote>>(syncExecution, new ExecutionDataflowBlockOptions { SingleProducerConstrained = true, MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded });
//Function that performs Sync Processing
Func<Tuple<Symbol, int>, List<Quote>> syncExecution = new Func<Tuple<Symbol, int>, List<Quote>>(partitionTuple =>
{
Symbol symbol = partitionTuple.Item1;
int partitionIndex = partitionTuple.Item2;
//Read Binary Data
byte[] byteArray = binaryDataReaders[symbol].ReadBytes(partitionIndex);
//Deserialize and return quote list
List<Quote> quoteList = dataInterfaces[symbol].Deserialize(symbol, byteArray);
return quoteList;
});
这就是我发布到变换块的方式:
quoteBuffer.SendAsync(new Tuple<Symbol, int>(symbol, counter));
原始问题:
有人用以下自定义变换块帮助了我。想法是发布/发送同步TInput并以异步方式对TInput进行操作,而自定义转换块在返回转换后的项目时保留已发布项目的顺序。例如,如果在相应的顺序中发布1,2,3并且变换函数对每个输入进行平方并返回项目,则正确的输出值和顺序应为1,4,9,而不管3变换中的哪一个操作完成时。
但是,我怀疑代码有错误,因为输出顺序不正确。更糟糕的是,混乱的订单位置是随机的,这使得调试变得更加困难,但却反映了这样一个事实:显然,将输入元素转换为输出元素的任务完全不同。
有人可以看看,并可能提供一些我在这里缺少的提示吗?感谢
public static IPropagatorBlock<TInput, TOutput> CreateConcurrentOrderedTransformBlock<TInput, TOutput>(Func<TInput, TOutput> transform)
{
var queue = new TransformBlock<Task<TOutput>, TOutput>(t => t);
var processor = new ActionBlock<Tuple<TInput, Action<TOutput>>>(
tuple => tuple.Item2(transform(tuple.Item1)),
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded
});
var enqueuer = new ActionBlock<TInput>(
async item =>
{
var tcs = new TaskCompletionSource<TOutput>();
await processor.SendAsync(
new Tuple<TInput, Action<TOutput>>(item, tcs.SetResult));
await queue.SendAsync(tcs.Task);
});
enqueuer.Completion.ContinueWith(
_ =>
{
queue.Complete();
processor.Complete();
});
return DataflowBlock.Encapsulate(enqueuer, queue);
}
答案 0 :(得分:0)
我回答我自己的问题,因为我发现了导致所有这些麻烦的错误。从我的lambda表达式中可以看出,我读取了数据块中的字节数组,这意味着只要并行度设置为> 1字节,就会同时从物理磁盘中读取同一文件中的数组。这显然非常混淆了读取字节的位置。我用br.basestream.seek(...)设置读操作的起点,并通过br.readbytes(numberBytes)读取字节。由于几个操作同时影响文件中的位置,二进制读取器很可能以无序方式读取字节,这导致混乱。
我通过将二进制读取器拉出lambda表达式来解决问题,而是将读取字节数组传递到表达式中,并仅使用并发进行反序列化和合并/排序,从而解决了问题。是的,变换块保留了顺序。感谢svick在tpl数据流方面分享您的丰富专业知识。