意外行为 - TPL DataFlow BatchBlock在执行TriggerBatch时拒绝项目

时间:2016-02-25 12:12:13

标签: c# tpl-dataflow

当您创建具有有界容量的批处理块并调用triggerBatch时(并行)发布新项目 - 在触发批处理执行时间期间发布新项目将失败。

调用触发批处理(每隔X次)是为了确保在输入数据流暂停或减速的情况下数据在块中不会延迟太长时间。

以下代码将输出一些“post failure”事件。 例如:

    public static void Main(string[] args)
    {
        var batchBlock = new BatchBlock<int>(10, new GroupingDataflowBlockOptions() { BoundedCapacity = 10000000 });
        var actionBlock = new ActionBlock<int[]>(x => ProcessBatch(x), new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = 1 });
        batchBlock.LinkTo(actionBlock);

        var producerTask = Task.Factory.StartNew(() =>
        {
            //Post 10K Items
            for (int i = 0; i < 10000; i++)
            {
                var postResult = batchBlock.Post(i);
                if (!postResult)
                    Console.WriteLine("Failed to Post");
            }
        });

        var triggerBatchTask = Task.Factory.StartNew(() =>
            {                    
                //Trigger Batch..
                for (int i = 0; i < 1000000; i++)
                    batchBlock.TriggerBatch();
            });

        producerTask.Wait();
        triggerBatchTask.Wait();
    }

    public static void ProcessBatch(int[] batch)
    {
        Console.WriteLine("{0} - {1}", batch.First(), batch.Last());
    }

*请注意,只有当batchBlock有界时,此方案才可重现。

我是否遗漏了某些内容,或者这是否与batchBlock有关?

1 个答案:

答案 0 :(得分:4)

BatchBlock并没有真正拒绝该项目,它会尝试推迟该项目。除了在Post()的情况下,推迟不是一种选择。解决此问题的一种简单方法是使用await batchBlock.SendAsync(i)代替batchBlock.Post(i)(这也意味着您需要将Task.Factory.StartNew(() =>更改为Task.Run(async () =>)。

为什么会这样?根据{{​​3}},如果BatchBlock有界,TriggerBatch()将被异步处理,并且在处理时,不会接受任何新项目。

在任何情况下,您都不应期望Post()始终在有界区块上返回true,如果区块已满,Post()也将返回false