关于c#:TPL数据流块永远不会在PropagateCompletion上完成

TPL Dataflow block never completes on PropagateCompletion

自从对传播完成管道进行最后一次更改以来,我的一个缓冲区块从未完成。让我总结一下正在起作用的东西和不再起作用的东西:

以前的工作方式:

1
2
3
4
5
6
A.LinkTo(B, PropagateCompletion);
B.LinkTo(C, PropagateCompletion);
C.LinkTo(D, PropagateCompletion);
D.Receive();

// everything completes

不再工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
A.LinkTo(B, PropagateCompletion);
C.LinkTo(D, PropagateCompletion);

await A.Completion;
someWriteOnceBlock.Post(B.Count);
// B.Complete(); commented on purpose
B.LinkTo(C, PropagateCompletion);

D.Receive();

// Only A reaches completion
// B remains in 'waiting for activation'
// C executes but obviously never completes since B doesn't either

如果我取消注释行,则一切正常,但显然该行不是必需的。

以某种方式,即使链接到它的块已完成并传播其完成,我的BufferBlock B也永远不会完成,并且从其链接的块会接收所有缓冲的项目。


通过等待A的完成,直到A完成为止,其余代码均不会执行。这就是await的工作方式-将其package后的代码以连续的形式package起来,以准备完成等待的代码。因此,在这种情况下,B在A完成之后链接到A,所以我认为不会传播完成。


我遇到了同样的问题-我的最后一个方块是一个TransformBlock,它正坐在那儿等待完成。

只有通过调用block.Complete或将完成沿链传播的方式,只有没有剩余要处理的输入,已处理完所有输出且已完成的块,该块才会完成。

我通过使最后一个块为ActionBlock来解决此问题,因为这不会产生任何输出。这是我的代码,它使用一系列文本文件并反序列化其内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Dim maxDop = Environment.ProcessorCount
Dim executionOptions = New ExecutionDataflowBlockOptions With {.MaxDegreeOfParallelism = maxDop}
Dim linkOptions = New DataflowLinkOptions With {.PropagateCompletion = True}

Dim inputBlock = New BufferBlock(Of String)
Dim transformBlock = New TransformBlock(Of String, IEnumerable(of JsonObject))(Function(fileName) DeserialiseFromFileAsync(fileName)
Dim outputBlock As New BufferBlock(Of IEnumerable(of JsonObject))
Dim combineBlock = New ActionBlock(Of IEnumerable(of JsonObject))(Sub(col) ' Do something to add all the collections together)

inputBlock.LinkTo(transformBlock, linkOptions)
transformBlock.LinkTo(outputBlock, linkOptions)
outputBlock.LinkTo(combineBlock, linkOptions)

For fileNo = 1 To 10
    inputBlock.Post(String.Concat("JsonFile", fileNo,".txt"))
Next

inputBlock.Complete() '
Complete the first block, propogation will handle the rest
Await combineBlock.Completion 'Await the last block completing