“有界”BatchBlock => ActionBlock。如何完成正确的方法?

时间:2015-07-16 09:45:54

标签: c# .net task-parallel-library tpl-dataflow

我正在尝试使用链接到操作块的有界批处理块。 我知道批处理块中的项目进料结束时我想触发完成链。

问题是:如果我的BatchBlock<T>属于给定的BoundedCapacity,我将无法在操作块中触发所有项目。

以下是我的问题的一个示例,它应该(在我对TPL数据流的理解......)中打印0到124,但最终打印0到99.

必须有一些我遗漏的东西......也许BoundedCapacity意味着“当队列数量超过xxx时丢弃项目......”如果是这样的话,我怎样才能实现有保证的最大内存消耗?

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks.Dataflow;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            int itemsCount = 125;
            List<int> ints = new List<int>(itemsCount);
            for (int i = 0; i < itemsCount; i++)
                ints.Add(i);

            BatchBlock<int> batchBlock = new BatchBlock<int>(50,new GroupingDataflowBlockOptions(){BoundedCapacity = 100});
            ActionBlock<int[]> actionBlock = new ActionBlock<int[]>(intsBatch =>
            {
                Thread.Sleep(1000);
                foreach (int i in intsBatch)
                    Console.WriteLine(i);               
            });
            batchBlock.LinkTo(actionBlock, new DataflowLinkOptions() { PropagateCompletion = true });

            // feed the batch block
            foreach (int i in ints)
                batchBlock.Post(i);
            // Don't know how to end the proper way... Meaning it should display 0 to 124 and not 0 to 99
            batchBlock.Complete();
            batchBlock.TriggerBatch();
            actionBlock.Completion.Wait();
        }
    }
}

1 个答案:

答案 0 :(得分:7)

块上的

Post并不总是成功。它会尝试将邮件发布到阻止,但如果达到BoundedCapacity则会失败并返回false

你可以做的是使用SendAsync代替它返回一个等待的任务。如果块有空间用于您的消息,则它将异步完成。如果它没有,那么该块返回一个任务,当它有空间接受新消息时将完成。您可以等待该任务并限制插入:

async Task MainAsync()
{
    var ints = Enumerable.Range(0, 125).ToList();
    var batchBlock = new BatchBlock<int>(50, new GroupingDataflowBlockOptions { BoundedCapacity = 100 });
    var actionBlock = new ActionBlock<int[]>(intsBatch =>
    {
        Thread.Sleep(1000);
        foreach (var i in intsBatch)
            Console.WriteLine(i);
    });
    batchBlock.LinkTo(actionBlock, new DataflowLinkOptions { PropagateCompletion = true });

    foreach (var i in ints)
        await batchBlock.SendAsync(i); // wait synchronously for the block to accept.

    batchBlock.Complete();
    await actionBlock.Completion;
}