国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python的Flask框架應用調用Redis隊列數據的方法

2019-11-25 16:45:16
字體:
來源:轉載
供稿:網友

任務異步化
打開瀏覽器,輸入地址,按下回車,打開了頁面。于是一個HTTP請求(request)就由客戶端發送到服務器,服務器處理請求,返回響應(response)內容。

我們每天都在瀏覽網頁,發送大大小小的請求給服務器。有時候,服務器接到了請求,會發現他也需要給另外的服務器發送請求,或者服務器也需要做另外一些事情,于是最初們發送的請求就被阻塞了,也就是要等待服務器完成其他的事情。

更多的時候,服務器做的額外事情,并不需要客戶端等待,這時候就可以把這些額外的事情異步去做。從事異步任務的工具有很多。主要原理還是處理通知消息,針對通知消息通常采取是隊列結構。生產和消費消息進行通信和業務實現。

生產消費與隊列
上述異步任務的實現,可以抽象為生產者消費模型。如同一個餐館,廚師在做飯,吃貨在吃飯。如果廚師做了很多,暫時賣不完,廚師就會休息;如果客戶很多,廚師馬不停蹄的忙碌,客戶則需要慢慢等待。實現生產者和消費者的方式用很多,下面使用Python標準庫Queue寫個小例子:

import randomimport timefrom Queue import Queuefrom threading import Threadqueue = 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()

大概輸出如下:

廚師 Thread-1 做了 1 飯 --- 還剩 1 飯沒賣完廚師 Thread-2 做了 8 飯 --- 還剩 2 飯沒賣完廚師 Thread-3 做了 3 飯 --- 還剩 3 飯沒賣完吃貨Thread-4 吃了 1 飯 --- 還有 2 飯可以吃吃貨Thread-5 吃了 8 飯 --- 還有 1 飯可以吃吃貨Thread-4 吃了 3 飯 --- 還有 0 飯可以吃廚師 Thread-1 做了 0 飯 --- 還剩 1 飯沒賣完廚師 Thread-2 做了 0 飯 --- 還剩 2 飯沒賣完廚師 Thread-1 做了 1 飯 --- 還剩 3 飯沒賣完廚師 Thread-1 做了 1 飯 --- 還剩 4 飯沒賣完吃貨Thread-4 吃了 0 飯 --- 還有 3 飯可以吃廚師 Thread-3 做了 3 飯 --- 還剩 4 飯沒賣完吃貨Thread-5 吃了 0 飯 --- 還有 3 飯可以吃吃貨Thread-5 吃了 1 飯 --- 還有 2 飯可以吃廚師 Thread-2 做了 8 飯 --- 還剩 3 飯沒賣完廚師 Thread-2 做了 8 飯 --- 還剩 4 飯沒賣完

Redis 隊列
Python內置了一個好用的隊列結構。我們也可以是用redis實現類似的操作。并做一個簡單的異步任務。

Redis提供了兩種方式來作消息隊列。一個是使用生產者消費模式模式,另外一個方法就是發布訂閱者模式。前者會讓一個或者多個客戶端監聽消息隊列,一旦消息到達,消費者馬上消費,誰先搶到算誰的,如果隊列里沒有消息,則消費者繼續監聽。后者也是一個或多個客戶端訂閱消息頻道,只要發布者發布消息,所有訂閱者都能收到消息,訂閱者都是ping的。

生產消費模式
主要使用了redis提供的blpop獲取隊列數據,如果隊列沒有數據則阻塞等待,也就是監聽。

import redisclass Task(object):  def __init__(self):    self.rcon = redis.StrictRedis(host='localhost', db=5)    self.queue = 'task:prodcons:queue'  def listen_task(self):    while True:      task = self.rcon.blpop(self.queue, 0)[1]      print "Task get", taskif __name__ == '__main__':  print 'listen task queue'  Task().listen_task()

發布訂閱模式
使用redis的pubsub功能,訂閱者訂閱頻道,發布者發布消息到頻道了,頻道就是一個消息隊列。

import redisclass Task(object):  def __init__(self):    self.rcon = redis.StrictRedis(host='localhost', db=5)    self.ps = self.rcon.pubsub()    self.ps.subscribe('task:pubsub:channel')  def listen_task(self):    for i in self.ps.listen():      if i['type'] == 'message':        print "Task get", i['data']if __name__ == '__main__':  print 'listen task channel'  Task().listen_task()

Flask 入口
我們分別實現了兩種異步任務的后端服務,直接啟動他們,就能監聽redis隊列或頻道的消息了。簡單的測試如下:

import redisimport randomimport loggingfrom flask import Flask, redirectapp = Flask(__name__)rcon = redis.StrictRedis(host='localhost', db=5)prodcons_queue = 'task:prodcons:queue'pubsub_channel = 'task:pubsub:channel'@app.route('/')def index():  html = """<br><center><h3>Redis Message Queue</h3><br><a href="/prodcons">生產消費者模式</a><br><br><a href="/pubsub">發布訂閱者模式</a></center>"""  return html@app.route('/prodcons')def prodcons():  elem = random.randrange(10)  rcon.lpush(prodcons_queue, elem)  logging.info("lpush {} -- {}".format(prodcons_queue, elem))  return redirect('/')@app.route('/pubsub')def pubsub():  ps = rcon.pubsub()  ps.subscribe(pubsub_channel)  elem = random.randrange(10)  rcon.publish(pubsub_channel, elem)  return redirect('/')if __name__ == '__main__':  app.run(debug=True)

啟動腳本,使用

siege -c10 -r 5 http://127.0.0.1:5000/prodconssiege -c10 -r 5 http://127.0.0.1:5000/pubsub

可以分別在監聽的腳本輸入中看到異步消息。在異步的任務中,可以執行一些耗時間的操作,當然目前這些做法并不知道異步的執行結果,如果需要知道異步的執行結果,可以考慮設計協程任務或者使用一些工具如RQ或者celery等。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 宁河县| 岳西县| 汉沽区| 沾益县| 徐汇区| 宁国市| 红河县| 灵寿县| 怀宁县| 诏安县| 凤城市| 清流县| 缙云县| 彰武县| 临西县| 武冈市| 崇文区| 靖远县| 芷江| 兴宁市| 邳州市| 澄城县| 福安市| 海丰县| 宣恩县| 平凉市| 温州市| 方城县| 茶陵县| 施秉县| 廉江市| 驻马店市| 蕉岭县| 九台市| 关岭| 桐柏县| 樟树市| 喀喇| 乐东| 临沭县| 淅川县|