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中使用PIPE操作Linux管道
Feb 04 Python
Python列表生成器的循环技巧分享
Mar 06 Python
在Python中用keys()方法返回字典键的教程
May 21 Python
详解Python 模拟实现生产者消费者模式的实例
Aug 10 Python
Python 实现一行输入多个值的方法
Apr 21 Python
python操作小程序云数据库实现简单的增删改查功能
Jun 06 Python
使用pyinstaller打包PyQt4程序遇到的问题及解决方法
Jun 24 Python
基于python实现蓝牙通信代码实例
Nov 19 Python
python处理RSTP视频流过程解析
Jan 11 Python
可视化pytorch 模型中不同BN层的running mean曲线实例
Jun 24 Python
python 实现汉诺塔游戏
Nov 28 Python
python 标准库原理与用法详解之os.path篇
Oct 24 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
收音机怀古---春雷3P7图片欣赏
2021/03/02 无线电
php查看请求头信息获取远程图片大小的方法分享
2013/12/25 PHP
php 创建以UNIX时间戳命名的文件夹(示例代码)
2014/03/08 PHP
PHP使用静态方法的几个注意事项
2014/09/16 PHP
Laravel框架实现的使用smtp发送邮件功能示例
2019/03/12 PHP
JavaScript 基础知识 被自己遗忘的
2009/10/15 Javascript
Javascript 设计模式(二) 闭包
2010/05/26 Javascript
YUI Compressor压缩JavaScript原理及微优化
2013/01/07 Javascript
兼容IE和FF的图片上传前预览js代码
2013/05/28 Javascript
js实现鼠标拖动图片并兼容IE/FF火狐/谷歌等主流浏览器
2013/06/06 Javascript
Jquery 改变radio/checkbox选中状态,获取选中的值(示例代码)
2013/12/12 Javascript
Node.js实现的简易网页抓取功能示例
2014/12/05 Javascript
js的toLowerCase方法用法实例
2015/01/27 Javascript
JS实现样式清新的横排下拉菜单效果
2015/10/09 Javascript
jQuery 弹出层插件(推荐)
2016/05/24 Javascript
javascript使用闭包模拟对象的私有属性和方法
2016/10/05 Javascript
jQuery的ready方法实现原理分析
2016/10/26 Javascript
浅谈Nodejs中的作用域问题
2016/12/26 NodeJs
javascript循环链表之约瑟夫环的实现方法
2017/01/16 Javascript
vue仿淘宝滑动验证码功能(样式模仿)
2019/12/10 Javascript
Vue实现背景更换颜色操作
2020/07/17 Javascript
django开发教程之利用缓存文件进行页面缓存的方法
2017/11/10 Python
Python对List中的元素排序的方法
2018/04/01 Python
计算机二级python学习教程(3) python语言基本数据类型
2019/05/16 Python
Python Numpy 实现交换两行和两列的方法
2019/06/26 Python
Python获取、格式化当前时间日期的方法
2020/02/10 Python
python打开音乐文件的实例方法
2020/07/21 Python
CSS3 3D制作实战案例分析
2016/09/18 HTML / CSS
HTML5触摸事件实现移动端简易进度条的实现方法
2018/05/04 HTML / CSS
Marc Jacobs彩妆官网:Marc Jacobs Beauty
2017/07/03 全球购物
澳大利亚宠物商店:Petbarn
2017/11/18 全球购物
I.T集团香港官方商城:ITeSHOP.com Hong Kong
2019/02/15 全球购物
英语生日邀请函
2014/01/23 职场文书
2014年情人节活动方案
2014/02/16 职场文书
追悼会主持词
2014/03/20 职场文书
2014年作风建设剖析材料
2014/10/23 职场文书