如何在TPL Dataflow中将多个目标块与源块链接?

14

我原以为以下代码可以从两个发布者(publishers)那里都输出结果,但实际上只从第一个发布者那里输出结果:

我期望以下代码可以从两个发布者那里都得到输出,但它仅从第一个发布者那里输出结果:

var broadcastBlock = new BroadcastBlock<int>(null);
var transformBlock = new TransformBlock<int, int>(i => i*10);
var publish1 = new ActionBlock<int>(i => Console.WriteLine("Publisher 1:" + i));
var publish2 = new ActionBlock<int>(i => Console.WriteLine("Publisher 2:" + i));

broadcastBlock.LinkTo(transformBlock, new DataflowLinkOptions() { PropagateCompletion = true });
transformBlock.LinkTo(publish1, new DataflowLinkOptions() { PropagateCompletion = true });
transformBlock.LinkTo(publish2, new DataflowLinkOptions() { PropagateCompletion = true });

foreach (var i in Enumerable.Range(0, 5))
{
    broadcastBlock.Post(i);
}
broadcastBlock.Complete();
Task.WhenAll(publish1.Completion, publish2.Completion).Wait();

我显然在这里缺少一些基本的东西,有什么想法吗?

2个回答

20

你正在将2个ActionBlock链接到一个TransformBlock。你应该将这2个ActionBlock链接到BroadcastBlock,然后将BroadcastBlock链接到TransformBlock

你的情况:

BroadCast => Transfrom => ActionBlock
                       => ActionBlock

你需要什么:

Transfrom => BroadCast => ActionBlock
                       => ActionBlock

4
有些块可以链接到多个目标,但它们不会将项目“复制”到所有目标。对于每个项目,它们只发布到一个目标。BroadcastBlock会将项目提供给所有目标,直到其项目更改。 - i3arnon
4
据我理解,BroadcastBlock 只向所有目标块提供 最新的 值。这意味着如果此示例中的 TransformBlock 有新值, ActionBlocks 可能不会接收到所有的值,尤其是如果它们消耗的时间比 TransformBlock 生产的时间长的话。 - urbanhusky
1
@urbanhusky 它只提供最新的接收,但它将传递到每个可以接受消息的链接目标块。请参阅文档。在底部:"BroadcastBlock<T>确保当前元素在允许覆盖元素之前广播到任何链接的目标。" - Marc L.
@urbanhusky 哎呀。根据我对上述文档的阅读,它似乎确保将数据传递到所有接受的链接目标缓冲区(例如,缓冲区不会满)。 (当然,“保证”受到RAM的耐久性,运行时稳定性等限制。我通常会引用Tommy Boy中的经典语录来告诉消费者,)你有反例吗?如果有的话,也许你或我应该开另一个问题。 - Marc L.
1
你正在将两个 ActionBlocks 链接到一个 TransformBlock。你应该将这两个 ActionBlock 链接到 BrodcastBlock,然后将 BroadcastBlock 链接到 TransformBlockLinkTo 方法是从 source 指向 target,而不是相反。因此,我认为答案的措辞有些令人困惑。不过图示是正确的。 - Theodor Zoulias
显示剩余4条评论

0

我无法在上面发表评论,但我认为我的BroadcastBlock的发现对某些人会有用:

  • 只要您广播到没有设置“DataflowBlockOptions.BoundedCapacity”的块,那么所有消息都将被传递。
  • 确保您的源块是您链接的最后一个块。如果您首先链接它,则可能会创建竞争条件。源和广播块可以在链接目标块之前处理消息。这将取决于应用程序,但在我的微不足道的测试中,我只会在我的目标/操作块中看到最后一条消息。

编辑:注意到我的第二个评论与OP无关,因为它们的结构方式,但这是我遇到的问题,因为我的SourceBlock是在任务中填充的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接