I have issues with a list collection that is passed into a broadcast block. Here is what I have so far (pseudo code as the complete code base is too long):
private BroadcastBlock<List<Quote>> tempBCB;
private TransformBlock<List<Quote>, Dictionary<int, IParentOrder>> tfb1;
private TransformBlock<List<Quote>, Dictionary<int, IParentOrder>> tfb2;
private BatchBlock<Dictionary<int, IParentOrder>> batchBlock;
private JoinBlock<List<Quote>, Dictionary<int, IParentOrder>[]> joinBlock;
private TransformBlock<Tuple<List<Quote>,
Dictionary<int, IParentOrder>[]>,List<MySignal>> transformBlock;
tempBCB = new BroadcastBlock<List<Quote>>(quoteList => {
return quoteList;
//return Cloning.CloneListCloneValues<Quote>(quoteList);
});
tfb1 = new TransformBlock<List<Quote>, Dictionary<int, IParentOrder>>(
quotes => {//do something and return Dictionary<int, IParentOrder>});
tfb2 = new TransformBlock<List<Quote>, Dictionary<int, IParentOrder>>(
quotes => {//do something and return Dictionary<int, IParentOrder>});
batchBlock = new BatchBlock<Dictionary<int, IParentOrder>>(2);
joinBlock = new JoinBlock<List<Quote>, Dictionary<int, IParentOrder>[]>(
new GroupingDataflowBlockOptions { Greedy = false });
transformBlock = new TransformBlock<Tuple<List<Quote>,
Dictionary<int, IParentOrder>[]>, List<MySignal>>(
tuple => { //do something and return List<MySignal>;});
//Linking
tempBCB.LinkTo(tfb1);
tempBCB.LinkTo(tfb2);
tfb1.LinkTo(batchBlock);
tfb2.LinkTo(batchBlock);
tempBCB.LinkTo(joinBlock.Target1);
batchBlock.LinkTo(joinBlock.Target2);
joinBlock.LinkTo(transformBlock);
My problem is that with the current implementation of tempBCB I get strange results in the final TransformBlock<TInput, TOutput>.
For example the Dictionary<int, IParentrOrder> collections as part of the tuple are NOT of equal size even the implementations of tfb1 and tfb2 are 100% identical.
The commented-out line in the tempBCB implementation does a deep copy of the broadcasted list and that does seem to solve the problem but the issue is that this deep copy makes my code about 10 times slower, which is on such magnitude that I need to find a different solution.
First of all I am not absolutely sure that this is the problem or that its just this slow down which causes the concurrent operations to perform as expected even though a bug is still hiding in there.
Secondly, if the lack of a deep copy in the broadcast block causes those problems how can I make it faster?
Here is my deep copy code:
public static List<TValue> CloneListCloneValues<TValue>(List<TValue> original)
where TValue : ICloneable
{
List<TValue> ret = new List<TValue>(original.Count);
foreach (TValue entry in original)
{
ret.Add((TValue)entry.Clone());
}
return ret;
}
I could potentially feed a Quote[] instead of List<Quote> into the broadcast block, but I do not see how it would help to speed up performance of the deep copy.
My questions are:
- Is the deep copy issue the real issue here (I doubt because the
List<Quote>, streamed into the broadcast block is never altered by any of the transform blocks)? - If yes why and how can I make the deep copy more efficient?
I answer my own question because I solved the problem eventually. The issue as svick cautioned was not related to whether
List<Quote>required a deep copy in the broadcastBlock or not (in fact it did not require a deep copy). The problem was related to the broadcastBlock which was requested to complete (complete propagation set to true to linked data flow blocks) before batchBlock, which also links to the joinBlock, potentially streamed all items to joinBlock. I simply took out joinBlock because I rewrote the transform blocks (they now return their own transformed items as well as the original item as well making the joinBlock obsolete.Note on concurrency in the main transformBlock: setting MaxDegreeOfParallelism to > 1 already provides performance benefits even with this light workload, however, it really kicks in when throwing heavier workloads at it.
Here the complete code which compiles and works (I renamed some classes but the structure remains as described):
I hope this helps others who may struggle with similar issues. I love TPL Dataflow and svick in particular really helped and motivated me to dig deeper. Thank you svick!!!