TPL Dataflow是否适用于此设计类型?

时间:2013-04-07 11:04:29

标签: c# .net task-parallel-library dataflow

我目前正在研究如何模拟连接对象之间的资源和消息传输,例如通过网络系统传输设备或控制消息:

enter image description here CLICK FOR LARGER IMAGE.

我最近一直在研究TPL Dataflow,不是因为它的线程和并行性,而是它在没有大型杂乱代码处理边缘情况的情况下如何实现数据流水线操作。模拟只能每500ms左右运行一次,并且实际上不是时间关键。

我一直在玩图书馆,现在已经阅读过几次文档,但我很难用它来实现解决方案。在上面描述的节点概念中,我不确定什么适合Dataflow节点。

我希望得到一些关于TPL Dataflow是否适合这里的建议,如果是这样的话,那么Dataflow Block对应的每个图像节点的基本实现。

2 个答案:

答案 0 :(得分:5)

我认为TPL Dataflow并不适合。有几个原因:

  1. TDF没有双工(双向)通信,你会以某种方式将其固定。
  2. 在TDF中,块通常接收消息,然后生成更多要沿管道发送的消息。这似乎不是你需要的(除了你的中心节点),至少不是逻辑上的。
  3. 但我认为您的要求不需要像TDF那样重量级的东西。我想你应该做的是:

    1. 为消息发送创建一个简单的库,可能使用类似客户端 - 服务器的体系结构:客户端(例如,消费者节点或分发节点)向服务器(例如分发节点或电源节点)发送消息,服务器回复,可能会有一些延迟。如果客户端连接到多个服务器,它会向所有服务器发送相同的消息,并决定如何处理多个响应(可能只接受第一个响应;这也意味着客户端必须能够拒绝响应)。
    2. 创建一个存储电源的PowerStore类,可用于获取电源。它将返回Task,因此消费者可以等到电源可用。
    3. 使用以上两点,构建节点应该相对简单。

答案 1 :(得分:2)

经过深思熟虑,原型设计和研究我终于使用Events和Delegates实现了解决方案,并且工作得很好!

唯一的主要设计问题是,如果例如3个分布节点以三角形连接,则会出现消息进入无限循环的情况。或者,如果某个节点连接到自身,或者两个节点连接不止一次。 我在事件监听器连接中用一些简单的逻辑覆盖了每个边缘情况:

public bool ConnectTo(Node peerNode)
        {
            EthernetPort peerPort   = peerNode.GetFreePort();
            EthernetPort myPort     = this.GetFreePort();

            // Perform a check for free ports for both peers:
            if (peerPort == null || myPort == null)
                return false; // Either myself or my peer do not have a spare port.

            // Perform a check to make sure these nodes aren't already connected:
            if (this.HasConnectedNode(peerNode))
                return false;

            // Connect the two ports:
            myPort.Connect(peerNode, peerPort);
            peerPort.Connect(this, myPort);
            return true;
        }
public bool HasConnectedNode(Node node) {
            foreach (var port in ethernetSwitch.ethernetPorts)
            {
                if (port.peerNode == node)
                    return true; // Found a port already connected to this node.
            }

            return false; // No port has this node connected to it.
        }

最后,为了防止错过某些内容或只是感到安全,我实施了一个带有EventArgs变量的自定义int timeToLive类型。每次节点处理消息时,此变量都会递减,如果它达到0,则会丢弃该消息。