首页 > 解决方案 > ZeroMQ:如何在 ZeroMQ 节点中处理与消息无关的异步事件?

问题描述

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

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

应该如何编写主循环,使其在任一类型的事件(即消息的接收和异步事件的发生)上唤醒?

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

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

其次,我将两个事件的阻塞代码移动到单独的线程中。相反,在主循环中,我睡在一个信号量(或条件变量)上,它​​是由任一事件的发生发布的。这就是我在传统应用程序中采用的方式,但 Pieter Hintjens 编写的ZeroMQ 指南非常明确地指出使用信号量:

远离经典的并发机制,如互斥锁、临界区、信号量等。这些是 ZeroMQ 应用程序中的反模式。

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

标签: multithreadingasynchronouszeromqdistributed-computingdistributed-system

解决方案


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

如果事件不是通过可用于 ZMQ 轮询的文件描述符引发的(例如,Windows 上的串行端口准备好读取),我通常使用线程将事件转换为通过 ZMQ 套接字发送的消息。工作得很好。变得不可移植,但这是不可避免的。

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


推荐阅读