I have a chain of TPL Dataflow blocks and would like to observe progress somewhere inside the system.
I am aware that I could just jam a TransformBlock
The issue with your code is that you're wiring up two consumers of block1
. Dataflow is then just giving a value to which ever consumer is there first.
So you need to broadcast the values from block1
into two other blocks to then be able to consume those independently.
Just a side note, don't do .Publish().RefCount()
as it doesn't do what you think. It will effectively make a one run only observable that during that one run will allow multiple observers to connect and see the same values. It has nothing to do with the source of the data nor how the Dataflow blocks interact.
Try this code:
// Set up mesh
var block1 = new TransformBlock(i => i + 20);
var block_boadcast = new BroadcastBlock(i => i, new DataflowBlockOptions());
var block_buffer = new System.Threading.Tasks.Dataflow.BufferBlock();
var block2 = new ActionBlock(i => Debug.Print("block2:" + i.ToString()));
var obs = block_buffer.AsObservable();
var l1 = block1.LinkTo(block_boadcast);
var l2 = block_boadcast.LinkTo(block2);
var l3 = block_boadcast.LinkTo(block_buffer);
// Progress
obs.Subscribe(i => Debug.Print("progress:" + i.ToString()));
// Start
var vals = Enumerable.Range(1, 5);
foreach (var v in vals)
{
block1.Post(v);
}
block1.Complete();
That gives me:
block2:21 block2:22 block2:23 block2:24 block2:25 progress:21 progress:22 progress:23 progress:24 progress:25
Which is what I think you wanted.
Now, just as a further aside, using Rx for this might be a better option all around. It's much more powerful and declarative than any TPL or Dataflow option.
Your code boils down to this:
Observable
.Range(1, 5)
.Select(i => i + 20)
.Do(i => Debug.Print("progress:" + i.ToString()));
.Subscribe(i => Debug.Print("block2:" + i.ToString()));
That pretty much gives you same result.