Python的Flask框架应用调用Redis队列数据的方法


Posted in Python onJune 06, 2016

任务异步化
打开浏览器,输入地址,按下回车,打开了页面。于是一个HTTP请求(request)就由客户端发送到服务器,服务器处理请求,返回响应(response)内容。

我们每天都在浏览网页,发送大大小小的请求给服务器。有时候,服务器接到了请求,会发现他也需要给另外的服务器发送请求,或者服务器也需要做另外一些事情,于是最初们发送的请求就被阻塞了,也就是要等待服务器完成其他的事情。

更多的时候,服务器做的额外事情,并不需要客户端等待,这时候就可以把这些额外的事情异步去做。从事异步任务的工具有很多。主要原理还是处理通知消息,针对通知消息通常采取是队列结构。生产和消费消息进行通信和业务实现。

生产消费与队列
上述异步任务的实现,可以抽象为生产者消费模型。如同一个餐馆,厨师在做饭,吃货在吃饭。如果厨师做了很多,暂时卖不完,厨师就会休息;如果客户很多,厨师马不停蹄的忙碌,客户则需要慢慢等待。实现生产者和消费者的方式用很多,下面使用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()

大概输出如下:

厨师 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 redis

class 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", task

if __name__ == '__main__':
  print 'listen task queue'
  Task().listen_task()

发布订阅模式
使用redis的pubsub功能,订阅者订阅频道,发布者发布消息到频道了,频道就是一个消息队列。

import redis


class 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 redis
import random
import logging
from flask import Flask, redirect

app = 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/prodcons
siege -c10 -r 5 http://127.0.0.1:5000/pubsub

可以分别在监听的脚本输入中看到异步消息。在异步的任务中,可以执行一些耗时间的操作,当然目前这些做法并不知道异步的执行结果,如果需要知道异步的执行结果,可以考虑设计协程任务或者使用一些工具如RQ或者celery等。

Python 相关文章推荐
Python获取远程文件大小的函数代码分享
May 13 Python
Python使用设计模式中的责任链模式与迭代器模式的示例
Mar 02 Python
Django压缩静态文件的实现方法详析
Aug 26 Python
python做反被爬保护的方法
Jul 01 Python
python tkinter控件布局项目实例
Nov 04 Python
python3读取csv文件任意行列代码实例
Jan 13 Python
浅谈pytorch torch.backends.cudnn设置作用
Feb 20 Python
详解Python 最短匹配模式
Jul 29 Python
如何用PyPy让你的Python代码运行得更快
Dec 02 Python
python 实现的IP 存活扫描脚本
Dec 10 Python
python Polars库的使用简介
Apr 21 Python
提取视频中的音频 Python只需要三行代码!
May 10 Python
Python第三方库的安装方法总结
Jun 06 #Python
在Python程序和Flask框架中使用SQLAlchemy的教程
Jun 06 #Python
Python的socket模块源码中的一些实现要点分析
Jun 06 #Python
深入浅析python定时杀进程
Jun 06 #Python
深入理解python函数递归和生成器
Jun 06 #Python
python下调用pytesseract识别某网站验证码的实现方法
Jun 06 #Python
浅析AST抽象语法树及Python代码实现
Jun 06 #Python
You might like
提高PHP编程效率 引入缓存机制提升性能
2010/02/15 PHP
php删除文件夹及其文件夹下所有文件的函数代码
2013/01/23 PHP
zf框架的Filter过滤器使用示例
2014/03/13 PHP
强制PHP命令行脚本单进程运行的方法
2014/04/15 PHP
Javascript学习笔记二 之 变量
2010/12/15 Javascript
40个有创意的jQuery图片、内容滑动及弹出插件收藏集之一
2011/12/31 Javascript
jQuery中ready事件用法实例
2015/01/19 Javascript
JavaScript页面模板库handlebars的简单用法
2015/03/02 Javascript
JavaScript使用yield模拟多线程的方法
2015/03/19 Javascript
JavaScript整除运算函数ceil和floor的区别分析
2015/04/14 Javascript
javascript常用函数(2)
2015/11/05 Javascript
快速学习jQuery插件 Form表单插件使用方法
2015/12/01 Javascript
JS获取input file绝对路径的方法(推荐)
2016/08/02 Javascript
vue-router命名视图的使用讲解
2019/01/19 Javascript
vue.js表单验证插件(vee-validate)的使用教程详解
2019/05/23 Javascript
echarts多条折线图动态分层的实现方法
2019/05/24 Javascript
在vue中使用image-webpack-loader实例
2020/11/12 Javascript
[06:10]6.81新信使新套装!给你一个炫酷的DOTA2
2014/05/06 DOTA
[02:10]DOTA2 TI10勇士令状玩法及不朽Ⅰ展示:焕新世界,如你所期
2020/05/29 DOTA
Python中的文件和目录操作实现代码
2011/03/13 Python
python实现猜单词小游戏
2020/05/22 Python
对Python中list的倒序索引和切片实例讲解
2018/11/15 Python
Python一个简单的通信程序(客户端 服务器)
2019/03/06 Python
Django框架验证码用法实例分析
2019/05/10 Python
Python过滤序列元素的方法
2020/07/31 Python
python 邮件检测工具mmpi的使用
2021/01/04 Python
CSS3颜色值RGBA与渐变色使用介绍
2020/03/06 HTML / CSS
解决H5的a标签的download属性下载service上的文件出现跨域问题
2019/07/16 HTML / CSS
英国最大的奢侈珠宝和手表网站:C W Sellors
2017/02/10 全球购物
全球领先的美容用品专卖店:Beauty Plus Salon
2018/09/04 全球购物
打架检讨书50字
2014/01/11 职场文书
表扬信格式
2014/01/12 职场文书
年终奖发放方案
2014/06/02 职场文书
2014年卫生监督工作总结
2014/12/09 职场文书
2014年基建工作总结
2014/12/12 职场文书
2016应届毕业生实习心得体会
2015/10/09 职场文书