All the server software that I have been involved with is heavily based on the idea of a processing queue. Messages are added to the queue, and a processing thread takes items off the queue and does something with them, perhaps adding to other queues in the process. If there is nothing on the queue then the processing thread just waits until something is placed there.
In the transaction processing software I am working on at the moment, there is an incoming messages queue. A thread takes those messages and reliably distributes ("despatches") those messages to the processing threads, which do most of the work. The processing threads then add messages to an outgoing queue, which has a sending thread that sends the transformed messages to the other system (sometimes one message becomes many, or many become one).
In fact, because the two main connections are both bidirectional, there is an inbound and an outbound queue for both sides of the application. The processing threads process messages in both directions, because then the relevant state can be kept in the same thread and does not need to be guarded by locks.
The way that messages are distributed to threads was carefully chosen so that messages can easily be associated with a certain thread by an identifier that is part of each message.This means messages can be sent to the right queue easily, and allows use of the thread-local, unguarded state.
This concept is so important that Erlang is based on it. So is Go. In that language, the message queues that I have been discussing above are called "channels" and processing threads are called "coroutines", and are declared with the "go" keyword.
No comments:
Post a Comment