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

S.R*_*ond 5 .net c# dataflow task-parallel-library

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

在此输入图像描述 点击获取更大的图片.

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

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

我想知道TPL Dataflow是否适合这里,如果是这样,Dataflow Block对应的每个图像节点的基本实现.

svi*_*ick 5

我不认为TPL Dataflow能很好地适应这种情况.有几个原因:

  1. TDF没有双工(双向)通信,你会以某种方式将其固定.
  2. 在TDF中,块通常接收消息,然后产生更多消息以沿管道发送.这似乎不是您需要的(除了您的中心节点),至少在逻辑上是这样.

但我认为您的要求不需要像TDF那样重量级的东西.我想你应该做的是:

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


S.R*_*ond 2

经过深思熟虑、原型设计和研究,我终于使用事件和委托实现了该解决方案,并且效果非常好!

唯一的主要设计问题是,如果例如将 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.
        }
Run Code Online (Sandbox Code Playgroud)

最后,为了以防万一我错过了某些东西或者只是为了感到安全,我EventArgsint timeToLive变量实现了自定义类型。每次节点处理消息时,该变量都会递减,如果它达到 0,则消息将被丢弃。