异步任务: 很多时候服务器做的事情不需要客户端等待,所以可以把这些任务异步去做,主要原理是处理通知消息,然后针对通知消息通常是采取的队列结构。
实现消费者和生产者的方式很多,可以使用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)
订阅这个频道,并且打印出收到的消息