Подходящий шаблон сообщений Zmq для взаимодействующих процессов

Я использую библиотеку pyzmq для установления связи между двумя процессами Python на одном компьютере. Глядя на доступные шаблоны обмена сообщениями, предлагаемые ZMQ, неясно, какой из них подходит.
В моем случае оба процесса должны отправлять сообщения друг другу независимо в некоторые случайные моменты времени. По сути, в разные моменты каждый процесс является одновременно клиентом и сервером. Некоторое визуальное описание ниже. введите здесь описание изображения

Для реализации этого шаблона я использую два сокета ZMQ.PAIR. Каждый процесс имеет .bind()-s сокет для получения и .connect()-s для другого к .send() всякий раз, когда возникает необходимость.
Аналогичным образом у каждого есть выделенный поток для обработки получение, которое блокирует.

Однако этот дизайн кажется мне немного натянутым, и мне интересно, есть ли установка более естественная и подходящая для этого сценария? Я также предполагаю, что это должно быть довольно распространенным явлением. В текущем дизайне мне также не нравится то, что мне нужно вручную заботиться об очистке двух сокетов, когда процессы заканчиваются.


person steve    schedule 12.10.2015    source источник


Ответы (1)


Если узлы буквально идентичны (по крайней мере, с точки зрения того, как они видят друг друга для целей связи, т.е. нет настоящего «надежного» сервера для других «временных» клиентов), у вас есть два варианта:

(A) Разверните две пары сокетов, одна пара, которая рассматривает один узел как сервер, а другой — как клиент, а другая — наоборот.

Это может быть уместно, если связь между узлами следует строгому шаблону, например. один узел инициирует связь, и до конца этого конкретного разговора происходит определенное движение вперед и назад. Это позволяет каждому узлу независимо инициировать связь и поддерживать свою собственную частоту связи, не путая ее с «перекрестными помехами», инициированными другим узлом.

Это также более уместно, если когда-нибудь может быть более двух узлов, для создания звездообразной топологии, где каждый узел может напрямую связываться с каждым другим узлом. Существует ограничение на количество узлов, с которыми это может разумно работать, за пределами которого вы захотите реализовать какой-то центральный брокер.

(B) Просто выберите один узел в качестве "сервера", а другой узел в качестве "клиента", bind() и connect() соответственно, и после этого просто относитесь к ним как к равным

Это больше всего похоже на то, что вы ищете. Вам не нужно слишком беспокоиться о том, какая сторона bind()s, а какая connect()s. На данный момент это звучит так, как будто вы открываете и закрываете соединение каждый раз, когда вам нужно общаться. Вам следует подумать о том, чтобы просто оставить соединение открытым на время жизни вашего процесса. Сокеты PAIR, которые вы используете, поддерживают полностью неструктурированную связь, поэтому вы можете свободно отправлять и получать данные в любом направлении, независимо от того, какую сторону вы назначите своим «сервером», а какую сторону вы назначите своим «клиентом».

person Jason    schedule 13.10.2015
comment
В случае A) видно, что для каждого процесса задействовано 2 сокета. Для случая B) мне не ясно, имеете ли вы в виду один или два сокета на процесс. Один сокет подразумевал бы, что пока поток ожидает получения в сокете, какой-то другой поток попытается записать. Если возможно, я бы предпочел этот вариант, поскольку им проще управлять, но безопасно ли использовать сокет zmq таким образом? - person steve; 14.10.2015
comment
Сокеты ZMQ не являются потокобезопасными, поэтому вам не следует совместно использовать один сокет несколькими потоками (за исключением некоторых ограниченных условий, если вы знаете, что делаете, см. второй вопрос здесь). Так что нет, это не безопасно. Вам нужно использовать блокировку получения? Есть варианты не блокировать. Если вы блокируете свой принимающий сокет, то этот сокет просто должен быть выделен для приема, и вам понадобится другой сокет для отправки, если только я не ошибаюсь в вашей архитектуре. - person Jason; 14.10.2015
comment
Я думаю, что мне нужно заблокировать. Я не могу предвидеть, когда другой процесс отправит что-то. Если я не могу зарегистрировать обратный вызов для получения/обработки материала. - person steve; 14.10.2015
comment
Я рекомендую вам еще немного прочитать об общих настройках в python — обычно связь обрабатывается в цикле, который позволяет вам выполнять неблокирующую попытку получения каждый тик. Вы часто будете видеть такой цикл в примерах, хотя любая дополнительная работа в примере тривиальна. Использование ZMQ в контексте блокировки, насколько я знаю, редкость. - person Jason; 14.10.2015