【问题标题】:TPL Dataflow, how to forward items to only one specific target block among many linked target blocks?TPL Dataflow,如何将项目转发到多个链接目标块中的一个特定目标块?
【发布时间】:2012-11-28 06:35:30
【问题描述】:

我正在寻找一种 TPL 数据流块解决方案,它可以容纳多个项目,它可以链接到多个目标块,但它能够将项目仅转发到通过过滤器的特定目标块/谓词。任何时候都不应将一个项目同时交付给多个目标块,始终只交付给与过滤器匹配的那个,否则该项目可以被丢弃。我不喜欢 BroadCastBlock,因为如果我理解正确,它不能保证交付(或者是吗?)并且过滤是在目标块端完成的,这意味着 BroadCastBlock 基本上将每个项目的副本发送到所有链接到目标块。如果我理解正确的话,它在任何时候都不会超过一件。我不想使用 Post/Async 但维护一个 LinkTo 链。

有没有办法绕过完整的自定义数据流块?还是我误解了 BroadCastBlock 的工作原理?不幸的是,没有太多的文档可以详细介绍并涵盖用例。任何想法都受到高度赞赏。

【问题讨论】:

    标签: c# task-parallel-library actor message-passing tpl-dataflow


    【解决方案1】:

    如果我对您的理解正确,您想要的可以通过一个简单的BufferBlock 来完成,它将通过谓词链接到您的所有目标块。您还可以(无条件地)将其链接到 NullTarget block,以丢弃不匹配的项目。

    类似:

    var forwarder = new BufferBlock<SomeType>();
    forwarder.LinkTo(target1, item => matchesTarget1(item));
    forwarder.LinkTo(target2, item => matchesTarget2(item));
    forwarder.LinkTo(DataflowBlock.NullTarget<SomeType>());
    

    这样,每个项目将被发送到第一个匹配的目标,如果有的话。

    BroadcastBlock 如果您想将每个项目发送到多个目标,或者如果您想在目标块不够快的情况下丢弃项目,那么BroadcastBlock 会很有用。

    使用BroadcastBlock,如果没有块接受项目,则项目可能会被丢弃(即使他们稍后可能会接受)。但它不会随机丢弃项目,因此如果您的目标块没有设置BoundedCapacity,我认为您可以确定他们会获得所有他们不会拒绝的项目(例如,通过在@987654329 中使用谓词@)。

    【讨论】:

    • 这在技术上是如何工作的?是否每个目标都被尝试直到匹配,如果没有,它会阻塞内存,除非被空目标块刷新?并且我首先链接到哪个目标块的顺序然后下一个...重要吗?
    • 是的,每个目标都是按顺序尝试的。如果没有目标匹配,则该项目将留在缓冲区块中。在这种情况下,堵塞内存并不是什么大问题,堵塞管道才是。换句话说,这意味着在有问题的项目被某个目标接受之前,不会从该区块发送其他项目。这就是为什么NullTarget 块是必要的。是的,顺序很重要,这也是为什么你可以specify if you want to append or prepend each target to the list
    • 你真的是去重新 TDF 的人。惊人的。非常感谢。您是否广泛使用 TPL 数据流,或者为什么该库的深入知识(以及其他主题)?您之前提到您不隶属于 MS 并发团队。
    • SVick 正在迅速成为 TDF 答案的 Paul Erdős。我敢肯定,几年后,我们将使用 SVick 数字来衡量我们的同行和他之间的协作距离......; )
    • @svick 如果目标块具有无限容量,则此答案是正确的。如果目标是有界的,并且您希望源块自己限制而不是丢弃消息,则空目标应该有一个谓词,该谓词是先前目标谓词的否定。
    【解决方案2】:

    我发现接受的答案不正确。 NullTarget 应该与它的谓词联系起来,即消费者的否定。否则你可能会丢弃你想消费的消息。

    var forwarder = new BufferBlock<SomeType>();
    forwarder.LinkTo(target1, item => matchesTarget1(item));
    forwarder.LinkTo(target2, item => matchesTarget2(item));
    forwarder.LinkTo(DataflowBlock.NullTarget<SomeType>(), item => !matchesTarget1(item) && !matchesTarget2(item));
    

    【讨论】:

    • 能否详细说明邮件丢失的情况?过滤器是按顺序应用的,所以,如果链接按正确的顺序完成,就没有办法丢弃有效的消息,对吧?
    • @VMAtm 最后,是否按顺序链接?只是想确定..
    • @VMAtm 如果您的目标块具有有限容量并且输入队列已满,则源块无法判断它是否因为谓词或队列已满而被拒绝。如果您的最终目的地是没有谓词的空目标,这将导致“丢弃”消息。我为此浪费了很多时间,因为似乎每一篇关于 Dataflow 的文章都把这个细节弄错了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-25
    • 1970-01-01
    • 1970-01-01
    • 2022-12-21
    相关资源
    最近更新 更多