c# - TransformBlock 永远不会完成

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

我正试图围绕 TPL 数据流 block 中的“完成”进行思考。特别是,TransformBlock 似乎从未完成。为什么?

示例程序

我的代码计算从 1 到 1000 的所有整数的平方。为此我使用了一个 BufferBlock 和一个 TransformBlock。在我的代码后面,我等待 TransformBlock 完成。但是,该 block 从未真正完成,我不明白为什么。

static void Main(string[] args)
{
    var bufferBlock = new BufferBlock<int>();
    var calculatorBlock = new TransformBlock<int, int>(i =>
    {
        Console.WriteLine("Calculating {0}²", i);
        return (int)Math.Pow(i, 2);
    }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 8 });

    using (bufferBlock.LinkTo(calculatorBlock, new DataflowLinkOptions { PropagateCompletion = true }))
    {
        foreach (var number in Enumerable.Range(1, 1000))
        {
            bufferBlock.Post(number);
        }

        bufferBlock.Complete();

        // This line never completes
        calculatorBlock.Completion.Wait();

        // Unreachable code
        IList<int> results;
        if (calculatorBlock.TryReceiveAll(out results))
        {
            foreach (var result in results)
            {
                Console.WriteLine("x² = {0}", result);
            }
        }
    }
}

起初我以为我造成了僵局,但事实并非如此。当我在调试器中检查 calculatorBlock.Completion 任务时,它的 Status 属性设置为 WaitingForActivation。那是我大脑蓝屏的时刻。

最佳答案

您的管道挂起的原因是 BufferBlockTransformBlock 显然在清空项目之前不会完成(我猜 所需的行为IPropagatorBlocks 尽管我还没有找到关于它的文档)。

这可以用一个更小的例子来验证:

var bufferBlock = new BufferBlock<int>();
bufferBlock.Post(0);
bufferBlock.Complete();
bufferBlock.Completion.Wait();

除非您在完成之前添加 bufferBlock.Receive();,否则这会无限期地阻塞。

如果您在被 TryReceiveAll 代码块阻止之前从管道中删除了项目,则将另一个 ActionBlock 连接到管道,转换您的 TransformBlockActionBlock 或任何其他不再阻止的方式。


关于您的具体解决方案,您似乎根本不需要 BufferBlockTransformBlock,因为 block 本身有一个输入队列并且您不使用TransformBlock 的返回值。这可以通过 ActionBlock 实现:

var block = new ActionBlock<int>(
    i =>
    {
        Console.WriteLine("Calculating {0}²", i);
        Console.WriteLine("x² = {0}", (int)Math.Pow(i, 2));
    },
    new ExecutionDataflowBlockOptions {MaxDegreeOfParallelism = 8});
foreach (var number in Enumerable.Range(1, 1000))
{
    block.Post(number);
}
block.Complete();
block.Completion.Wait();

关于c# - TransformBlock 永远不会完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27187036/

相关文章:

C# 控制台应用程序 - 此操作需要交互式窗口站

c# - 获取 repo 中子文件夹的提交计数

.net - 控制错误的数据绑定(bind)

c# - .net 框架错误 (HRESULT 0x8007000B)

c# - 空 "using" block

c# - Visual Studio 2017 安装项目错误 2727

c# - BufferBlock 在 TryReceiveAll 之后与 OutputAvailableAsync 死锁

c# - 这个 TPL 习语存在吗?

c# - AsyncTaskMethodBuilder AwaitUnsafeOnCompleted 与等待时的 AwaitOnCompleted

c# - 在低于正常优先级的 Windows 服务中停止 Parallel.ForEach