redis-py包含一個PubSub對象,來訂閱頻道和監聽消息,建立PubSub對象很簡單python
>>> r = redis.StrictRedis(...) >>> p = r.pubsub()
一旦一個PubSub對象被建立,頻道channel和匹配模式(基於正則表達式的channel)就可以訂閱了
>>> p.subscribe('my-first-channel', 'my-second-channel', ...) >>> p.psubscribe('my-*', ...) 如今PubSub對象能夠訂閱這些頻道了,能夠從PubSub對象讀取消息來確認是否訂閱成功 >>> p.get_message() {'pattern': None, 'type': 'subscribe', 'channel': 'my-second-channel', 'data': 1L} >>> p.get_message() {'pattern': None, 'type': 'subscribe', 'channel': 'my-first-channel', 'data': 2L} >>> p.get_message() {'pattern': None, 'type': 'psubscribe', 'channel': 'my-*', 'data': 3L}
從PubSub對象讀取的消息時一個包含一下鍵的字典
正則表達式
type:能夠是如下值中的一個redis
‘subscribe’, ‘unsubscribe’, ‘psubscribe’, ‘punsubscribe’, ‘message’, ‘pmessage’網絡
channel:訂閱或取消訂閱的頻道或者消息要發送的頻道socket
pattern: 匹配一個信息頻道的模式,除了'pmessage'其餘狀況下都是none測試
data:消息數據,對於(非)訂閱消息,這個值會是當前訂閱的channel和匹配模式鏈接的數量,對於[p]message,這個值就是發送的消息編碼
如今就能夠發送消息了spa
發送方法返回channel匹配和模型pattern匹配的數量 # 'my-first-channel' 匹配 'my-first-channel' channel訂閱和'my-*' pattern訂閱 #因此這些消息會被傳送給2個channel或pattern >>> r.publish('my-first-channel', 'some data') 2 >>> p.get_message() {'channel': 'my-first-channel', 'data': 'some data', 'pattern': None, 'type': 'message'} >>> p.get_message() {'channel': 'my-first-channel', 'data': 'some data', 'pattern': 'my-*', 'type': 'pmessage'}
對於取消訂閱,和訂閱同樣,若是沒有傳遞參數,會取消全部訂閱線程
>>> p.unsubscribe() >>> p.punsubscribe('my-*') >>> p.get_message() {'channel': 'my-second-channel', 'data': 2L, 'pattern': None, 'type': 'unsubscribe'} >>> p.get_message() {'channel': 'my-first-channel', 'data': 1L, 'pattern': None, 'type': 'unsubscribe'} >>> p.get_message() {'channel': 'my-*', 'data': 0L, 'pattern': None, 'type': 'punsubscribe'}
redis-py 也容許你註冊一個回調功能來控制消息發佈.消息控制器只有一個參數,message,就像上面例子同樣是一個字典.用消息控制器訂閱頻道channel或者匹配樣式pattern,傳送channel或pattern做爲關鍵字參數,值做爲回調功能
code
當使用消息控制器從channel或pattern讀取消息時,消息字典被建立並傳遞給消息控制器.這種狀況下,因爲消息已經被處理,get_message()返回一個None值
>>> def my_handler(message): ... print 'MY HANDLER: ', message['data'] >>> p.subscribe(**{'my-channel': my_handler}) # 讀取訂閱確認信息 >>> p.get_message() {'pattern': None, 'type': 'subscribe', 'channel': 'my-channel', 'data': 1L} >>> r.publish('my-channel', 'awesome data') 1 #因爲消息控制器的做用,咱們須要告訴實例讀取數據,能夠有多種方式處理, #這裏咱們只使用get_message() >>> message = p.get_message() MY HANDLER: awesome data #注意這裏my_handler回調打印了上面的字符串 # `message`是 None 由於消息被控制器控制了 >>> print message None
若是你的應用不關心訂閱/取消訂閱確認消息(有時候是噪音),你能夠傳一個 ignore_subscribe_messages=True給 r.pubsub().這會引發全部的訂閱非訂閱消息讀取,但不會出如今你的應用中
>>> p = r.pubsub(ignore_subscribe_messages=True) >>> p.subscribe('my-channel') >>> p.get_message() #隱藏了訂閱消息,返回None >>> r.publish('my-channel') 1 >>> p.get_message() {'channel': 'my-channel', data': 'my data', 'pattern': None, 'type': 'message'}
有三種不一樣的讀取消息的策略
上面的例子使用pubsub.get_message().在這種場景,get_message()使用系統的'select'模式快速測試鏈接的socket.若是有數據能夠被讀取,get_message()會讀取它,處理後返回或者傳遞給消息處理器.若是沒有數據讀取,get_message()會馬上返回None.這使得整合到你的應用中一個已存的事件循環並不重要
>>> while True: >>> message = p.get_message() >>> if message: >>> # do something with the message >>> time.sleep(0.001) # be nice to the system :)
redis-py更老的版本只能用 pubsub.listen()讀取消息,listen()是一個生成器,會阻塞直到有消息能夠得到.若是你的應用不須要作任何事除了從redis接收消息,並對消息作出反應,listen()是一個簡單的運行方式
>>> for message in p.listen():... # do something with the message
第三種選擇是在單獨的線程裏運行一個事件循環, pubsub.run_in_thread() 建立一個新的線程並啓動事件循環.線程對象被返回給調用者run_in_thread().調用者可使用 thread.stop() 來關閉事件循環和線程.在這種場景下,運行線程的只是一個簡單的對get_message()的包裝器,尤爲是你建立一個小的非阻塞的事件循環. run_in_thread() 有一個可選擇的 sleep_time參數.若是被指定,事件循環會在每次循環迭代時用指定的值調用time.sleep()
注意,因爲咱們運行了一個單獨的線程,沒有辦法控制不是由註冊的消息控制器自動控制的消息.所以,若是你正在訂閱沒有消息控制器關聯的pattern或channel,redis-p會阻止你調用 run_in_thread()
>>> p.subscribe(**{'my-channel': my_handler}) >>> thread = p.run_in_thread(sleep_time=0.001) # 如今事件循環在後臺運行處理消息 # 當要關閉該線程時 >>> thread.stop()
一個PubSub對象綁定到一樣編碼的語義做爲它建立的客戶端實例.任何採用unicode的pattern和channel在發給Redis以前會被編碼爲指定的字符集.若是客戶端的解碼flag decode_responses被設定爲False(默認值),消息字典中的 ‘channel’, ‘pattern’ 和 ‘data’會變成byte字符串((Python 2時str, Python 3時byte).若是客戶端decode_responses 是True,‘channel’, ‘pattern’ 和 ‘data’值會使用客戶端的字符集自動解碼爲unicode字符
PubSub對象保存了他們訂閱的channel和pattern.在沒法鏈接的事件中,如網絡錯誤或超時,當從新鏈接時PubSub對象會從新訂閱全部的先前的channel和pattern.沒法鏈接期間發佈的消息沒法再呈現.當你要結束一個PubSub對象時,調用close()方法關閉鏈接
>>> p = r.pubsub() >>> ... >>> p.close()
Redis官方文檔https://pypi.python.org/pypi/redis/