TransformBlock永远不会完成 [英] TransformBlock never completes
问题描述
我试图把头放在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 IPropagatorBlock
s 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屋!