Flask框架及阻塞和非阻塞特性

0 小序

Flask是基于Python实现的轻量级Web应用框架,WSGI工具箱采用Werkzeug,模板引擎使用Jinja2,具有BSD授权.

1 应用

1.0 结构

flask_pure.py

from flask import Flask, render_template 

app = Flask(__name__)

@app.route('/')
def connect():
	return "connected test"
	
if __name__ == "__main__":
	app.run(host="0.0.0.0", port=8088, debug=True)

1.2 运行

python flask_pure.py
或者
python3 flask_pure.py
* Serving Flask app "flask_pure" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://0.0.0.0:8088/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 732-366-147

1.3 客户端调用

运行服务后,有一行提示,* Running on http://0.0.0.0:8088/ (Press CTRL+C to quit)即是该服务的运行地址,路由根据编写的逻辑进行修改及调用,终端运行是,使用Ctl + C退出服务.

http://0.0.0.0:8088/

2 Flask框架非阻塞特性

Flask实现的Web框架接口间是非阻塞的,即调用一个接口,不需要等待返回结果,可直接调用同一服务下的另一个接口,同一接口也是非阻塞的,即可实现并发.

2.1 验证

flask_pure.py

from flask import Flask, render_template 
import time

app = Flask(__name__)

@app.route('/')
def connect():
	return "connected test"

@app.route('/index')
def index_test():
	print("xindaqi")
	time.sleep(15)
	return render_template('index.html')

if __name__ == "__main__":
	app.run(host="0.0.0.0", port=8088, debug=True)

2.2 启动

python flask_pure.py
或者
python3 flask_pure.py
* Serving Flask app "flask_pure" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://0.0.0.0:8088/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 732-366-147

2.3 调用接口

先调用index,延迟15s,即让客户端等待15s,在15s内调用第二个接口

http://localhost:8088/index
http://localhost:8088/
http://localhost:8088/index
http://localhost:8088/index

2.4 结果

xindaqi
127.0.0.1 - - [27/Jan/2019 10:20:05] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Jan/2019 10:20:06] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Jan/2019 10:20:06] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Jan/2019 10:20:07] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Jan/2019 10:20:07] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Jan/2019 10:20:07] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Jan/2019 10:20:07] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Jan/2019 10:20:07] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Jan/2019 10:20:16] "GET /index HTTP/1.1" 200 -
xindaqi
xindaqi
127.0.0.1 - - [27/Jan/2019 11:35:29] "GET /index HTTP/1.1" 200 -
127.0.0.1 - - [27/Jan/2019 11:35:32] "GET /index HTTP/1.1" 200 -

2.5 分析

  • 由结果可见,调用第一个延迟15s的接口过程中,再调用其他接口,先返回能返回的结果;
  • 没有出现阻塞现象,即其他接口可实时返回结果;
  • 同时调用一个接口,不会出现阻塞,实现并发.

3 gevent的阻塞和非阻塞特性

gevent是一个基于协程的Python网络库,它使用greenlet在libev或libuv事件上提供高级同步API.
协程是单线程下的并发,又称微线程,是一种用户态的轻量级线程,即协程由用户程序自己控制调度;
协程切换开销小,属于程序级别的切换,操作系统无感知,因而更加轻量化,单线程内可实现并发效果,最大限度调用CPU.
协程本质是单线程实现,无法利用多核,可以一个程序开启多个进程,每个进程开启多个线程,每个线程内开启协程;一旦协程出现阻塞,将会阻塞整个线程.
特点:

  • 基于libev或libuv的快速事件循环
  • 基于greenlets轻量执行单元
  • 复用Python标准库
  • 支持SSL与socket通信
  • 通过线程池,dnspython或c等语言实现DNS查询
  • 通过Monkey Patching实现调用第三方模块
  • 支持TCP/UDPHTTP服务
  • 支持进程及线程池

3.1 阻塞

3.1.0 Demo

flask_wsgi.py

from flask import Flask, render_template
from gevent.pywsgi import WSGIServer
import time

app = Flask(__name__)

@app.route('/')
def connect():
	return "connected test"

@app.route('/index')
def index_test():
	time.sleep(15)
	return render_template('index.html')

if __name__ == "__main__":
	server  = WSGIServer(("0.0.0.0", 8089), app)
	print("Server started")
	server.serve_forever()

3.1.2 调用接口

先调用index,延迟15s,即让客户端等待15s,在15s内调用第二个接口

http://localhost:8088/index
http://localhost:8088/

3.1.3 结果

Server started
127.0.0.1 - - [2019-01-27 10:49:52] "GET /index HTTP/1.1" 200 240 15.028027
127.0.0.1 - - [2019-01-27 10:49:52] "GET / HTTP/1.1" 200 130 0.001366

3.1.4 分析

  • 该程序未使用monkey
  • 由结果可见,调用第一个延迟15s的接口过程中,再调用其他接口,出现阻塞,直到第一个接口获取返回值后,第二个接口才有结果返回;
  • 出现阻塞现象,即其他接口等待15s才能返回;

3.2 非阻塞

monkey将标准socket模块中的函数与类替换为对用的功能项,这样即使不清楚gevent结构,也可从多个greenlet运行环境中受益.

3.2.1 Demo

flask_wsgi.py

from flask import Flask, render_template
from gevent.pywsgi import WSGIServer
from gevent import monkey
import time

monkey.patch_all()
app = Flask(__name__)

@app.route('/')
def connect():
	return "connected test"

@app.route('/index')
def index_test():
	time.sleep(15)
	return render_template('index.html')

if __name__ == "__main__":
	server  = WSGIServer(("0.0.0.0", 8089), app)
	print("Server started")
	server.serve_forever()

3.2.2 调用接口

先调用index,延迟15s,即让客户端等待15s,在15s内调用第二个接口

http://localhost:8088/index
http://localhost:8088/

3.2.3 结果

Server started
127.0.0.1 - - [2019-01-27 11:09:28] "GET / HTTP/1.1" 200 130 0.000891
127.0.0.1 - - [2019-01-27 11:09:28] "GET / HTTP/1.1" 200 130 0.001959
127.0.0.1 - - [2019-01-27 11:09:37] "GET /index HTTP/1.1" 200 240 15.016904

3.2.4 分析

  • 该程序使用monkey
  • 由结果可见,调用第一个延迟15s的接口过程中,再调用其他接口,先返回能返回的结果;
  • 没有出现阻塞现象,即其他接口可实时返回结果;

4 总结

  • Flask框架可实现接口间,及同一接口的非阻塞;
  • genvent用于实现socket通信,借助monkey可实现接口间及接口通信的非阻塞,即socket客户端可实时接入,多个客户端可非阻塞获取数据,若不使用monkey则会出现客户端调用同一接口时阻塞;
  • 流程简单,无注释;

[参考文献]
[1]http://flask.pocoo.org/
[2]http://www.gevent.org/


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天然玩家

坚持才能做到极致

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值