ZeroMQ:如何处理ZeroMQ节点中与消息无关的异步事件?

时间:2018-06-14 11:41:39

标签: multithreading asynchronous zeromq distributed-computing distributed-system

假设我有一个带有ZeroMQ接口的节点(进程,线程,等等),让我们说一个 REP 套接字。这意味着我有一个无限的主循环,它在zmq_recvzmq_poll函数中休眠。

现在该节点还应该从另一个异步事件接收数据。想象一下,例如键盘按钮按下事件或切换GPIO引脚或定时器到期。在等待这些事件时,执行也必须休眠。

如何写入主循环,以便它唤醒任何类型的事件,即接收消息和发生异步事件?

我可以想到两个解决方案:

首先是轮询循环,其中两个事件都以非阻塞方式进行检查,并且每隔几毫秒运行一次循环。就处理负荷而言,这似乎并不理想。

其次,我将两个事件的阻塞代码移动到单独的线程中。在主循环中,我睡在信号量(或条件变量)上,该信号量由任一事件的出现发布。这就是我在传统应用程序中的用法,但是Pieter Hintjens编写的ZeroMQ Guide非常明确地使用信号量而不是

  

远离像互斥体这样的经典并发机制,   关键部分,信号量等。这些是反模式的   ZeroMQ应用程序。

那该怎么办?这里的最佳做法是什么?

3 个答案:

答案 0 :(得分:1)

根据您的操作系统,系统中的大多数事件都是通过某些文件描述符准备好读取而生成的。这通常是它在Linux,Unix等上的工作原理。例如,键盘输入通过STDIN进入。当然,任何描述的文件描述符都可以包含在ZMQ轮询中。

如果没有通过可以在ZMQ轮询中使用的文件描述符引发事件(例如,Windows上的串行端口准备好读取),我通常使用线程将事件转换为通过ZMQ发送的消息插座。效果很好。变得不便携,但这是不可避免的。

GPIO可能会更难。如果没有某个驱动程序支持将ISR集成到操作系统的驱动程序堆栈中,那么您将不得不轮询它。

答案 1 :(得分:0)

  

应如何编写主循环,以便唤醒任何类型的事件,即接收消息和异步事件的发生?

你几乎已经回答了自己。并发事件循环是一个问题。 ZeroMQ允许一个人同时处理异步和同步检查的消息队列。

鉴于您的控制逻辑需要一些与时间相关的其他决策,任何进入任何阻塞状态都是非常糟糕的主意(即使帖子中的热门媒体和“帮助< / em>“ - 文件提供了几乎所有关于”解释“的阻塞状态SLOC的简单代码示例。编号编号

永远不要失去你的控制角色。第一个阻塞状态会从自己控件的域中删除您的代码。 No. No. No.

  

这里的最佳做法是什么?

即使你的控制策略是复杂的,细粒度的,无论如何,最好使用明确控制的时序部分,你可以第一次检测,使用{non-blocking |控制持续时间阻止} - 调用 .poll() ,显式{ACK'd | NACK'd}任何消息到达的存在,下一步您的处理策略可能会根据您的优先级,后处理持续时间和资源可用性状态来决定如何处理检测到的事件组合/或它们各自处理每个检测到的事件的后处理工作负载的相对性能仍处于控制环路硬限时间内。

这就是{soft |艰难的 - 实时系统工作。

ZeroMQ为正确和智能提供了一些技巧(使用零拷贝机制,使用每个相应Context()实例的嵌入式IO线程池的性能/延迟调整选项,使用几乎 -Zero-Latency inproc://传输级,在可行的情况下可以避免旧学校并发的花里胡哨...... Martin SUSTRIK已经发布了很多关于性能和更多细节的内容。)

奖金部分:

如果您的硬件资源似乎太弱而无法处理任何完全成熟的胖网络代理,那么仍然可以将您的系统组成为轻量级网络代理,使用零IO线程{{1 -s,通过系统的 War-Gaming-Control-Room Context() - s网格上进行通信,收集和维护态势感知,做出符合全局控制策略的决策,并从哪里发布相应的战略,战术和操作命令,协调分配并整理网格,以便在轻量级和任务专用几乎中进行最终执行自治代理人。

答案 2 :(得分:0)

0MQ风格的解决方案是使用第二个套接字通知主线程其他异步事件。然后将两个套接字传递给zmq_poll,当任一套接字中有消息时,将通知您的主线程。

例如,除了REP套接字之外,主线程还可以创建PULL套接字。它会将两者传递给zmq_poll,然后阻止等待消息。触发异步事件时,单独的线程可以将PUSH套接字连接到PULL,并将事件数据传递给等待的主线程。

有关如何轮询多个套接字的详细信息,请参阅zmq_poll docs