YAMAGUCHI::weblog

土足で窓から失礼いたします。今日からあなたの息子になります。 当年とって92歳、下町の発明王、エジソンです。

pyzmqでZeroMQを触ってみる (PUB/SUB)

はじめに

こんにちは、Python界の情弱です。前回に引き続きpyzmqでZeroMQを触ってみます。The Guideの流れに従ってREQ/REPの次はPUB/SUBをやってみました。

PUB/SUB

ZeroMQのガイドに載っているサンプルは天気予報を通知するPublisherと、それを受け取って特定の都市のデータだけフィルタして平均気温を表示するSubscriberがいるというやつだった。

コード
  • weathersrv(天気予報)
import zmq
import time
from random import randrange

context = zmq.Context()
publisher = context.socket(zmq.PUB)
publisher.bind("tcp://*:5556")

message_id = 0
while True:
  zipcode     = randrange(10001, 10010)
  temprature  = randrange(0, 215) - 80
  relhumidity = randrange(0, 50) + 10

  update = "%05d %d %d %d" % (zipcode, temprature, relhumidity, message_id)
  message_id += 1
  print update
  time.sleep(1.0)
  publisher.send(update)
  • weathercli
import zmq
import sys

context = zmq.Context()
subscriber = context.socket(zmq.SUB)
subscriber.connect("tcp://localhost:5556")

# receive only message with zipcode being 10001
zipfilter = sys.argv if len(sys.argv) > 1 else "10001 "
subscriber.setsockopt(zmq.SUBSCRIBE, zipfilter)

update_samples = 10
for updates in range(update_samples):
  message = subscriber.recv()
  zipcode, temprature, relhumidity, message_id = message.split()
  print ("zip:%s, temp:%s, relh:%s, id:%s" % 
         (zipcode, temprature, relhumidity, message_id))
  total_temp = float(temprature)

print ("average temprature for zipcode '%s' was '%f'" % 
       (zipfilter, total_temp / update_samples))
実行結果

まずSubscriberを2つ起動してからPublisherを起動する。

% python weathercli.py
% python weathercli.py

この状態でPublisher起動。

% python weathersrv.py

すると

  • weathersrv.py
% python weathersrv.py
10005 -23 33 0
10001 11 56 1
10006 124 33 2
10006 7 49 3
10007 115 57 4
10009 76 10 5
10001 106 20 6
10009 -69 43 7
10007 14 24 8
10009 -24 51 9
10006 -32 58 10
10007 62 59 11
10004 2 40 12
10006 110 30 13
10006 53 31 14
...

と表示されて、Subsriberの方は

  • weathercli.py (#1)
% python weathercli.py
zip:10001, temp:11, relh:56, id:1
zip:10001, temp:106, relh:20, id:6
zip:10001, temp:68, relh:57, id:21
zip:10001, temp:89, relh:34, id:34
zip:10001, temp:-73, relh:54, id:35
zip:10001, temp:45, relh:31, id:45
zip:10001, temp:-25, relh:12, id:48
zip:10001, temp:125, relh:27, id:62
zip:10001, temp:-29, relh:35, id:83
zip:10001, temp:48, relh:33, id:88
average temprature for zipcode '10001 ' was '4.800000'
  • weathercli.py (#2)
% python weathercli.py
zip:10001, temp:11, relh:56, id:1
zip:10001, temp:106, relh:20, id:6
zip:10001, temp:68, relh:57, id:21
zip:10001, temp:89, relh:34, id:34
zip:10001, temp:-73, relh:54, id:35
zip:10001, temp:45, relh:31, id:45
zip:10001, temp:-25, relh:12, id:48
zip:10001, temp:125, relh:27, id:62
zip:10001, temp:-29, relh:35, id:83
zip:10001, temp:48, relh:33, id:88
average temprature for zipcode '10001 ' was '4.800000'

と同じ値が表示されました。めでたし。

おまけ

最初Publisherのほうのコードをビジーループで実装してたらSubscriberが受信するメッセージが全然違ってしまってすごく焦った。