理解TPL数据流并行度排序度

时间:2016-08-26 18:23:29

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

我正在阅读Dataflow (Task Parallel Library),并且有一部分说:

  

如果指定的最大并行度大于1,则会同时处理多个消息,因此,可能无法按接收顺序处理消息。但是,从块输出消息的顺序将正确排序。

这意味着什么?

示例,我设置了具有并行度= 5的行动块:

testActionBlock = new ActionBlock<int>(i => Consumer(i),
            new ExecutionDataflowBlockOptions()
            {
                MaxDegreeOfParallelism = 5
            });

await Producer();
testActionBlock.Completion.Wait();

My Producer()基本上将数字排队到块中:

private async Task Producer()
{
    for (int i=0; i<= 1000; i++)
    {
        await testActionBlock.SendAsync(i);
    }
    testActionBlock.Complete();
}

而我的消费者(i)只写出了这些内容:

private async Task Consumer(int i)
{
    if (i == 1)
    {
        await Task.Delay(5000);
    }
    Console.WriteLine(i);
}

这是否意味着消费者(2)将被阻止,直到消费者(1)完成处理(因为有5秒的延迟)?我测试了代码,但似乎并非如此。即使我删除了5秒延迟,我也看不到输出是否正常。

[更新]

bBlock = new BufferBlock<int>(option);

testActionBlock = new ActionBlock<int>(i => Consumer(i),
    new ExecutionDataflowBlockOptions()
    {
        MaxDegreeOfParallelism = 5
    });

bBlock.LinkTo(testActionBlock);

await Producer();
testActionBlock.Completion.Wait();

My Producer()现在将添加到bBlock:

private async Task Producer()
{
    for (int i=0; i<= 1000; i++)
    {
        await bBlock.SendAsync(i);
    }
    bBlock.Complete();
}

那么,在这种情况下,消费者(1)将等待5秒,然后消费者(2)才能继续?

2 个答案:

答案 0 :(得分:3)

没有。您可以将DoP视为线程(不是完全容易想到的)

所以在5点,它会尝试一次处理5个。由于#1需要5秒钟,#2肯定会先完成。 #3,#4和#5可能也是如此。甚至可能是#6(因为#2已完成,DoP将允许它从#6开始)

即使没有延迟,也无法保证处理顺序。所以永远不要依赖他们执行的命令。话虽如此,当你使用消息输出( NOT prtinting,因为这是他们执行的顺序)时,它们将按照它们进入的顺序重新排序,即使它们是以任意方式执行的顺序。

答案 1 :(得分:1)

DataflowBlockOptions类包含一个可配置的属性EnsureOrdered

获取或设置一个值,该值指示是否应在块的消息处理上强制执行有序处理。

此属性确定块是否将按照接收到的消息的顺序输出已处理的消息,默认情况下为true。因此,TransformBlockTransformManyBlock之类的块会产生输出(实现ISourceBlock<TOutput>接口),在将它们传播到目标块时,它们会保留接收到的消息的原始顺序({{ 3}}个块,它们ITargetBlock<TInput>是)。

EnsureOrdered选项与邮件的处理顺序无关。例如,将属性linked设置为值MaxDegreeOfParallelism意味着所有接收到的消息都将被安排在到达后立即执行,并且-如果DataflowBlockOptions.Unbounded有足够的可用线程,则执行所有这些都将立即开始。将EnsureOrdered设置为false的效果是,一旦完成一条消息的执行,就可以向下游传播,即使之前收到的消息的执行尚未完成

EnsureOrdered选项对ThreadPool无效,因为这些块不会产生输出。这对ActionBlock也没有影响,因为尽管这些块产生输出,但它们不进行任何处理,因此没有任何事情会扭曲接收到的消息的原始顺序。简而言之,此属性仅对产生输出并执行处理的块有效。