異步任務: 很多時候服務器做的事情不需要客戶端等待,所以可以把這些任務異步去做,主要原理是處理通知消息,然後針對通知消息通常是採取的隊列結構。
實現消費者和生產者的方式很多,可以使用Python的標準庫Queue:
import random
import time
from Queue import Queue
from threading import Thread
queue = Queue(10)
class Producer(Thread):
def run(self):
while True:
elem = random.randrange(9)
queue.put(elem)
print "廚師 {} 做了 {} 飯 --- 還剩 {} 飯沒賣完".format(self.name, elem, queue.qsize())
time.sleep(random.random())
class Consumer(Thread):
def run(self):
while True:
elem = queue.get()
print "吃貨{} 吃了 {} 飯 --- 還有 {} 飯可以吃".format(self.name, elem, queue.qsize())
time.sleep(random.random())
def main():
for i in range(3):
p = Producer()
p.start()
for i in range(2):
c = Consumer()
c.start()
if __name__ == '__main__':
main()
Redis隊列
redis有兩種方式來實現消息隊列:
- 生產者消費模式(不推薦使用):讓一個或者多個客戶端監聽消息隊列,一旦消息達到,消費者馬上消費,誰先搶到就算誰的,如果消息隊列裏面沒有消息,那麼消費者就繼續監聽。
- 發佈訂閱模式:一個或者多個客戶端訂閱消息頻道,只要發佈者發佈消息,所有的訂閱者都會收到消息,訂閱者之間是平等的。
發佈訂閱者模式:
使用redis的pubsub功能,訂閱者訂閱頻道,發佈者發佈消息到頻道,頻道就是一個消息隊列:
class publisher():
def __init__(self, topic='', host='127.0.0.1', port=6379, db=0):
self.srv = redis.StrictRedis(host=host, port=port, db=0, charset='utf-8', decode_responses=True)
self.topic = topic # 這個topic就是發佈的頻道
def publish(self, msg=''):
self.srv.publish(self.topic, msg) # 往該頻道里面發佈消息
class subscriber():
def __init__(self, topic, host='127.0.0.1', port=6379, db=0):
self.srv = redis.StrictRedis(host=host, port=port, db=0, charset='utf-8', decode_responses=True)
self.pubsub = self.srv.pubsub(ignore_subscribe_messages=True)
self.pubsub.subscribe(topic) # 訂閱頻道爲topic
def listen(self):
for message in self.pubsub.listen():
print(message) # 這裏可以獲取頻道里面的每一條信息
yield message['data']
所以這裏實例化publisher()
傳入topic其實是創建topic頻道,調用它的.publish()
方法可以往頻道里面發佈信息。
實例化subscriber()
傳入topic其實是訂閱topic頻道,調用它的.listen()
方法可以獲取頻道里面發佈的消息。
使用上面構造的Pubsub類:
def p():
pub = publisher(topic='test')
while 1:
time.sleep(3)
pub.publish(msg='Hello, Test')
pt = threading.Thread(target=p)
pt.setDaemon(True)
pt.start()
創建一個名爲test的頻道,每過三秒鐘往頻道發送一條信息
sub = subscriber(topic='test')
listen = sub.listen()
for msg in listen:
print(msg)
訂閱這個頻道,並且打印出收到的消息