TransformBlock永远不会完成 [英] TransformBlock never completes

查看:58
本文介绍了TransformBlock永远不会完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图把头放在TPL Dataflow块中的完成"上.特别是, TransformBlock 似乎从未完成.为什么?

I'm trying to wrap my head around "completion" in TPL Dataflow blocks. In particular, the TransformBlock doesn't seem to ever complete. Why?

我的代码计算1到1000之间所有整数的平方.为此,我使用了 BufferBlock TransformBlock .在稍后的代码中,我等待 TransformBlock 的完成.障碍实际上从未完成,我也不明白为什么.

My code calculates the square of all integers from 1 to 1000. I used a BufferBlock and a TransformBlock for that. Later in my code, I await completion of the TransformBlock. The block never actually completes though, and I don't understand why.

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 .那是我的大脑蓝屏的时刻.

At first I thought I created a deadlock situation, but that doesn't seem to be true. When I inspected the calculatorBlock.Completion task in the debugger, its Status property was set to WaitingForActivation. That was the moment when my brain blue screened.

推荐答案

管道挂起的原因是 BufferBlock TransformBlock 显然要清空后才能完成本身的项目(我想 IPropagatorBlock s的期望行为,尽管我还没有找到有关它的文档).

The reason your pipeline hangs is that both BufferBlock and TransformBlock evidently don't complete until they emptied themselves of items (I guess that the desired behavior of IPropagatorBlocks although I haven't found documentation on it).

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

This can be verified with a more minimal example:

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

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

This blocks indefinitely unless you add bufferBlock.Receive(); before completing.

如果在通过 TryReceiveAll 代码块阻止之前从管道中删除项目,将另一个 ActionBlock 连接到管道,然后转换您的 TransformBlock 设置为 ActionBlock 或其他不再阻止的方式.

If you remove the items from your pipeline before blocking by either your TryReceiveAll code block, connecting another ActionBlock to the pipeline, converting your TransformBlock to an ActionBlock or any other way this will no longer block.

关于您的特定解决方案,似乎您根本不​​需要 BufferBlock TransformBlock ,因为块本身具有输入队列,并且您不使用 TransformBlock 的返回值.这可以通过 ActionBlock :

About your specific solution, it seems that you don't need a BufferBlock or TransformBlock at all since blocks have an input queue for themselves and you don't use the return value of the TransformBlock. This could be achieved with just an 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();

这篇关于TransformBlock永远不会完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆