简体   繁体   English

TPL 数据流 C# 等待所有链接块完成

[英]TPL Dataflow C# wait for all linked blocks to complete

I'm using TPL Dataflow to build a pipeline.我正在使用 TPL Dataflow 来构建管道。 This pipeline should logically do the following:此管道应在逻辑上执行以下操作:

  1. Start by processing multiple data items - let's say it's pollingBlock .从处理多个数据项开始——假设它是pollingBlock
  2. In case certain conditions are met pass one of the items (that has met the conditions) to certain block for further monitoring, let's say it's monitoringBlock .如果满足某些条件,则将其中一项(已满足条件)传递给某个块以进行进一步监控,假设它是monitoringBlock Each monitoringBlock can hold only 1 item, but there are multiple monitoringBlocks .每个monitoringBlock只能容纳 1 个 item,但有多个monitoringBlocks
  3. pollingBlock should keep processing all the items including the one posted in a while (true) manner. pollingBlock应该继续处理所有项目,包括以一段while (true)方式发布的项目。
  4. monitoringBlocks while occupied should not accept any other messages and these messages should just get deleted without further processing.被占用的monitoringBlocks块不应该接受任何其他消息,并且这些消息应该被删除而无需进一步处理。
  5. After some processing in monitoringBlock the message should either be marked as completed or transfer to the next block for processing, this next block is processingBlockmonitoringBlock中进行一些处理后,消息应该被标记为完成或者转移到下一个块进行处理,这个下一个块是processingBlock

A brief sample:一个简短的示例:

public Task ExecutePipeline()
{
    var block = CreatePollingPipeline();
    block.Post((_serviceOne, _serviceTwo));

    block.Complete();
    return block.Completion;
}

public ActionBlock<(IServiceOne serviceOne, IServiceTwo serviceTwo)> CreatePollingPipeline()
{
    var pollingAlertHolder = new BufferBlock<(string input1, string input2)>();

    var pollingBlock = new ActionBlock<(IServiceOne serviceOne, IServiceTwo serviceTwo)>(services =>
    {
        while (true)
        {
            Console.WriteLine("Posting to alert block");
            pollingAlertHolder.Post(("INP1", "INPVAL"));
            Thread.Sleep(2000);

            Console.WriteLine("Posting to alert block");
            pollingAlertHolder.Post(("INP1", "INPVAL"));
            Thread.Sleep(2000);

            Console.WriteLine("Posting to alert block");
            pollingAlertHolder.Post(("INP2", "INPVAL2"));
            Thread.Sleep(2000);

            Console.WriteLine("Posting to alert block");
            pollingAlertHolder.Post(("INP1", "INPVAL"));
            Thread.Sleep(2000);

            Console.WriteLine("Posting to alert block");
            pollingAlertHolder.Post(("INP1", "INPVAL"));
            Thread.Sleep(2000);

            Console.WriteLine("Posting to alert block");
            pollingAlertHolder.Post(("INP2", "INPVAL2"));
            Thread.Sleep(2000);
        }
    });

    var monitoringBlock = new TransformBlock<(string input1, string input2), (string input1, string input2)>(inputs =>
        {
            Console.WriteLine("monitoringBlock started");
            Thread.Sleep(5000);
            Console.WriteLine("monitoringBlock completed");

            return (inputs.input1, inputs.input2);
        },
        new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1, BoundedCapacity = 1 });

    pollingAlertHolder.LinkTo(monitoringBlock, new DataflowLinkOptions() { PropagateCompletion = true },
        inputs => inputs.input1 == "INP1" && inputs.input2 == "INPVAL");
    pollingAlertHolder.LinkTo(DataflowBlock.NullTarget<(string input1, string input2)>());

    var processingBlock = new ActionBlock<(string input1, string input2)>(i =>
    {
        Console.WriteLine("processingBlock started");
        Thread.Sleep(2000);
        Console.WriteLine("processingBlock completed");
    }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1, BoundedCapacity = 1 });
    monitoringBlock.LinkTo(processingBlock, new DataflowLinkOptions { PropagateCompletion = true });


    return pollingBlock;
}

My question is how do I keep monitoringBlock occupied until linked processingBlock finishes its' job?我的问题是如何在链接的processingBlock完成其工作之前保持monitoringBlock被占用? I don't want any items to be posted to monitoringBlock before the message finished the FULL processing cycle.在消息完成完整处理周期之前,我不希望将任何项目发布到monitoringBlock

As already mentioned in comments, you can simply encapsulate logic of monitoringBlock and processingBlock in one block, for example, you can achieve that via predefined Datablock.Encapsulate method.正如评论中已经提到的,您可以简单地将monitoringBlockprocessingBlock的逻辑封装在一个块中,例如,您可以通过预定义的Datablock.Encapsulate方法来实现。

However, if you don't want to do that, you can use AutoResetEvent or similar abstraction, and your code could be like this:但是,如果您不想这样做,您可以使用AutoResetEvent或类似的抽象,您的代码可能是这样的:

AutoResetEvent dataflowEvent = new AutoResetEvent(true);
var bufferBlock = new ActionBLock<(string input1, string input2)>(i =>
{
    dataflowEvent.WaitOne();
    monitoringBlock.Post(i);
});
var monitoringBlock = new TransformBlock<(string input1, string input2), (string input1, string input2)>(inputs =>
    {
        Console.WriteLine("monitoringBlock started");
        Thread.Sleep(5000);
        Console.WriteLine("monitoringBlock completed");

        dataflowEvent.Set();
        return (inputs.input1, inputs.input2);
    },
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1, BoundedCapacity = 1 });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM