Reputation: 53863
I've got a program which receives information from about 10 other (sensor reading) programs (all controlled by myself). I now want to make them communicate using ZeroMQ.
For most of the queues the important thing is that the central receiving program always has the latest sensor data, all older messages are not important anymore. If a couple messages get lost I don't care. So for all of them I started out with a separate PUB/SUB
socket; one for each program. But I'm not sure if that is the right way to do it. As far as I understand I have two options:
int
).string
which tells the receiving end what the message is about.All connections are on a PUB/SUB
basis, so creating one socket would well work out. I'm just not sure if that is the most efficient way to do it.
All tips are welcome!
Upvotes: 2
Views: 444
Reputation: 1
-
PUB/SUB
is fine and allows an easy conversion from N-sensors:1-logger into N-sensors:2+-loggers
- one might also benefit from a conceptual separation of a socket from an access-port, where more than one sockets may get connected
If not bound, due to system-integration constraints, to some early ZeroMQ API, there is a lovely feature exactly for this via a .setsockopt( ZMQ_CONFLATE, True )
method:
ZMQ_CONFLATE
: Keep only last message
If set, a socket shall keep only one message in its inbound/outbound queue, this message being the last message received/the last message to be sent.
IgnoresZMQ_RCVHWM
andZMQ_SNDHWM
options. Does not support multi-part messages, in particular, only one part of it is kept in the socket internal queue.
Unless your real-time control stability introduces some hard-real-time limit, the PUB
-side freely decides, how often a new value is instructed to .send()
to SUB
(-s). Here no magic is needed, the less with ZMQ_CONFLATE
option set on the internal outgoing queue managed.
The SUB
(-s) side receiver(s) will also benefit from the ZMQ_CONFLATE
option set on the internal incoming queue managed, but given a set of individual .bind()
-s instantiate separate landing ports for delivery of different individual sensoric readouts, your "last" values will remain consistently the "last"-readouts. If all readouts would go into a common landing pad, your receiving process will get masked-out ( lost ) all readouts but the one that was just accidentally the "last" right before .recv()
took place, which would not help much, would it?
If some I/O-performance related tweaking becomes necessary, the .Context( n_IO_threads )
+ ZMQ_AFFINITY
-mapping options may increase and prioritise the resources the ioDataPump
may harness for increased IO-performance
Upvotes: 3
Reputation: 8404
Unless you're up against a tight real time requirement there's not much point in having more sockets than necessary. ZMQ's fair queuing ought to take care of giving each sensor program equal attention (see Figure 6 in the guide)
If your sensor programs are on other devices connected by Ethernet, the ultimate performance of your programs is limited by the bandwidth of the Ethernet NIC in your computer. A single thread program handling a single PULL socket stands a good chance of being able to process the data coming in faster than it can transit the NIC.
If that's so, then you may as well stick to a single socket and enjoy the simpler code. It's not very hard dealing with multiple sockets, but it's far easier to deal with one. For example, with one single socket you don't have to tell each sensor program what network port to connect to - it can be a constant.
PUSH/PULL sounds like a more natural pattern for your situation than PUB/SUB, but that won't make much difference.
Lastness
Lastness is going to be your (potential) problem. The whole point of things like ZMQ is that they will deliver messages in the order they're sent. Thus you read a message, it is by definition the "last" message so far as the recipient is concerned. The recipient has no idea as to whether or not there is another message on the way, in transit.
This is a feature of Actor model architectures (which is what ZMQ is). Messages get buffered up in the transport, and there's no information about the newness of the message to be learned when it's read. All you know is that it was sent some time beforehand. There is no execution rendezvous with the sender.
Now, you either process it as if it is the last message, or you wait for a period of time to see if another one comes along before processing it. The easiest thing to do is to simply process each message as if it is the last.
Contrast this with a Communicating Sequential Processes architecture. It's basically the same as an Actor model architecture, except that the transport does not buffer messages. Message sends block until the recipient has called message read.
Thus when you read a message, the recipient knows that it the last one sent by the sender. And the sender knows that the message it has sent has been received at that very instant by the recipient. So the knowledge of lastness is absolute - the message received really is the last one sent.
However, unless you have something fairly heavyweight going on I wouldn't worry about it. You are quite likely to be able to keep up with your sensor data stream even if the messages you're reading aren't the latest in the queue.
You can nearly make ZMQ into CSP by setting the high water limit on the sending end's socket to 1. That means that you can buffer up at most 1 message. That's not the same as 0, and unfortunately setting the HWM to 0 means "unlimited size buffer".
Upvotes: 0