组播块TPL数据流

时间:2016-03-19 13:44:36

标签: c# tpl-dataflow

我需要将一个对象多播到多个路径

      producer
         |
      multicast
     |        |
 Process1   Process2
     |        |
   Writedb   WriteFile

广播块没有多大帮助,它只对PROCESS1进程2执行最新操作,如果进程2运行较晚,那么它将无法接收消息。

db writer和write file有不同的数据。

以下是代码段。

class Program
{
    public static void Main()
    {
        var broadCastBlock = new BroadcastBlock<int>(i => i);

        var transformBlock1 = new TransformBlock<int, string>(i =>
        {
            Console.WriteLine("1 transformblock called: {0}", i);
            //Thread.Sleep(4);
            return string.Format("1_ {0},", i);
        });

        var transformBlock2 = new TransformBlock<int, string>(i =>
        {
            Console.WriteLine("2 transformblock called: {0}", i);
            Thread.Sleep(100);
            return string.Format("2_ {0},", i);
        });

        var processorBlockT1 = new ActionBlock<string>(i => Console.WriteLine("processBlockT1 {0}", i));
        var processorBlockT2 = new ActionBlock<string>(i => Console.WriteLine("processBlockT2 {0}", i));

        //Linking
        broadCastBlock.LinkTo(transformBlock1, new DataflowLinkOptions { PropagateCompletion = true });
        broadCastBlock.LinkTo(transformBlock2, new DataflowLinkOptions { PropagateCompletion = true });
        transformBlock1.LinkTo(processorBlockT1, new DataflowLinkOptions { PropagateCompletion = true });
        transformBlock2.LinkTo(processorBlockT2, new DataflowLinkOptions { PropagateCompletion = true });

        const int numElements = 100;

        for (int i = 1; i <= numElements; i++)
        {
            broadCastBlock.SendAsync(i);
        }

        //completion handling

        broadCastBlock.Completion.ContinueWith(x =>
        {
            Console.WriteLine("Braodcast block Completed");
            transformBlock1.Complete();
            transformBlock2.Complete();
            Task.WhenAll(transformBlock1.Completion, transformBlock2.Completion).ContinueWith(_ =>
            {
                processorBlockT1.Complete();
                processorBlockT2.Complete();
            });
        });


        transformBlock1.Completion.ContinueWith(x => Console.WriteLine("Transform1 completed"));
        transformBlock2.Completion.ContinueWith(x => Console.WriteLine("Transform2 completed"));
        processorBlockT1.Completion.ContinueWith(x => Console.WriteLine("processblockT1 completed"));
        processorBlockT2.Completion.ContinueWith(x => Console.WriteLine("processblockT2 completed"));


        //mark completion
        broadCastBlock.Complete();
        Task.WhenAll(processorBlockT1.Completion, processorBlockT2.Completion).ContinueWith(_ => Console.WriteLine("completed both tasks")).Wait();


        Console.WriteLine("Finished");
        Console.ReadLine();
    }
}

通过广播保证投放的最佳方法是什么?即多播。

我应该只在两端插入两个缓冲区,然后使用它,以便缓冲区始终收集正在进行的内容,然后该过程可能需要一些时间来处理所有这些缓冲区?

1 个答案:

答案 0 :(得分:0)

BroadcastBlock保证将所有消息提供给所有链接的块。因此,这正是您所需要的。不过,您应该解决的是向BroadcastBlock提供消息的方式:

for (int i = 1; i <= numElements; i++)
{
    broadCastBlock.SendAsync(i); // Don't do this!
}

应该等待SendAsync方法。针对同一块,您不应有多个未决的SendAsync操作。这样做不仅破坏了有关接收消息顺序的所有保证,而且还极大地降低了内存效率。使用有界块的整个要点是通过限制块内部缓冲区的大小来控制内存使用。通过发出多个未等待的SendAsync命令,您可以通过创建不完整Task的外部动态缓冲区(每个任务重达数百个字节)来传播此消息,这些消息仅占其中的一小部分,从而规避了这种自我施加的限制。这个重量。通过首先将块限制在内部,可以更有效地在内部缓冲这些消息。

for (int i = 1; i <= numElements; i++)
{
    await broadCastBlock.SendAsync(i); // Now it's OK
}