繁体   English   中英

理解 TPL 数据流并行度排序

[英]Understanding TPL Dataflow Degree of Parallelism ordering

我正在阅读Dataflow (Task Parallel Library) ,其中有一部分内容是:

当您指定的最大并行度大于 1 时,将同时处理多条消息,因此,消息可能不会按接收顺序进行处理。 但是,从块中输出消息的顺序将是正确排序的。

这意味着什么?

例如,我将操作块设置为并行度 = 5:

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

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

我的 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);
}

这是否意味着 Consumer(2) 将被阻塞,直到 Consumer(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();

我的 Producer() 现在将添加到 bBlock:

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

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

不。您可以将 DoP 视为线程(不完全但简单的方式来思考它)

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

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

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

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

这个属性决定了块是否会按照收到消息的相同顺序输出处理过的消息,默认情况下是true 因此,像TransformBlockTransformManyBlock这样产生输出的块(实现ISourceBlock<TOutput>接口)在将接收到的消息传播到它们的目标块(它们链接到的ITargetBlock<TInput>块)时会保留接收到的消息的原始顺序。

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

EnsureOrdered选项对ActionBlock没有影响,因为这些块不产生输出。 它也对BufferBlock没有影响,因为虽然这些块产生输出,但它们不做任何处理,所以不会发生任何可能扭曲它们接收到的消息的原始顺序的事情。 简而言之,此属性仅对产生输出和执行处理的块有效。

暂无
暂无

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

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