注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

snoopyxdy的博客

https://github.com/DoubleSpout

 
 
 

日志

 
 

关于Flask的流响应和异步响应  

2015-01-07 17:36:38|  分类: python |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
原文:http://mortoray.com/2014/03/04/http-streaming-of-command-output-in-python-flask/

我们现在需要通过stream流将数据返回给客户端,如下的代码是一个简单的 flask 服务器代码,在跑他之前,需要先安装依赖

pip install flask shelljob

将它保存成为server.py,然后执行 python server.py 来运行:

import flask
from shelljob import proc

app = flask.Flask(__name__)

@app.route( '/stream' )
def stream():
    g = proc.Group()
    p = g.run( [ "bash", "-c", "for ((i=0;i<100;i=i+1)); do echo $i; sleep 1; done" ] )

    def read_process():
        while g.is_pending():
            lines = g.readlines()
            for proc, line in lines:
                yield line

    return flask.Response( read_process(), mimetype= 'text/plain' )

if __name__ == "__main__":
    app.run(debug=True)

我们将服务器启动起来,我们达到的效果就是每隔1秒钟,向客户端响应1个数字,持续100次
shelljob这个模块是用来简化python执行shell命令使用的,项目地址:

我们现在可以设置超时,下面是一个带上超时的 read_process 函数,每隔5秒,他将打印出一个interval字符串

def read_process():
        trigger_time = time.time() + 5
        while g.is_pending():
            lines = g.readlines()
            for proc, line in lines:
                yield line

            now = time.time()
            if now > trigger_time:
                yield "*** Interval"
                trigger_time = now + 5

但是这样的服务器代码会造成整个 flask 对外的服务阻塞掉,如果你使用另外一个 curl 请求到服务器,你将得不到任何的响应,只有等前一个请求响应了,才能处理后一个。

这时我就需要使用 gunicorn 和 eventlet,执行  pip install gunicorn eventlet 安装依赖,这是不要直接使用python来运行我们的服务器,执行如下命令:

unicorn -k eventlet stream_server:app

这时依旧不能够异步执行,我们需要在 import 其他依赖之后,加上“猴子补丁”:

import flask
from shelljob import proc

import eventlet
eventlet.monkey_patch()

app = flask.Flask(__name__)

这时候我们的python程序就可以正常响应了,我们在程序里可以这样写:

from flask import Flask
from werkzeug.contrib.fixers import ProxyFix
import gevent

app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello World!'

@app.route('/block')
def block():
    gevent.sleep(60)
    return 'Hello World!'


app.wsgi_app = ProxyFix(app.wsgi_app)
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=4000)

然后通过gunicorn启动项目,配置文件如下:

bind='0.0.0.0:4000'
workers=1
backlog=2048
worker_class="gevent" #sync, gevent, meinheld
debug=False
daemon=False

启动命令:

gunicorn -c async.conf async:app

这样我们先访问'/block'然后再访问'/'也不会被阻塞了。
  评论这张
 
阅读(3377)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016