Using AsObservable to observe TPL Dataflow blocks without consuming messages

前端 未结 4 1309
星月不相逢
星月不相逢 2021-01-18 06:54

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

4条回答
  •  天涯浪人
    2021-01-18 07:19

    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.

提交回复
热议问题