我正试图在TPL数据流块中围绕“完成”来思考。尤其是,TransformBlock似乎永远不会完成。为什么?
示例程序
我的代码计算从1到1000的所有整数的平方。我用了一个BufferBlock和一个TransformBlock来表示。稍后在我的代码中,我将等待TransformBlock的完成。但这个街区从来没有真正完工,我不明白为什么。

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在清空它们自己的项目之前显然不会完成(我猜IPropagatorBlock的期望行为,尽管我还没有找到相关文档)。
这可以用一个最小的例子来验证:

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

除非在完成之前添加bufferBlock.Receive();,否则此块将无限期阻塞。
如果在阻塞之前通过TryReceiveAll代码块、将另一个ActionBlock连接到管道、将TransformBlock转换为ActionBlock或任何其他方式从管道中移除项,则此操作将不再阻塞。
关于您的特定解决方案,似乎根本不需要BufferBlockTransformBlock,因为块本身有一个输入队列,并且您不使用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/

10-11 07:27