Python Web 框架选型
Python Web 框架有如下几种部署方式:
- WSGI
- ASGI
- 独立部署
- CGI/FastCGI
WSGI是最常见的接口,由PEP333和PEP3333规范定义,获得了最广泛的支持。
WSGI接口的上游是HTTP Server,下游是WSGI应用,而提供WSGI服务的程序被称为WSGI容器。生产环境中常见的WSGI容器有Gunicorn、uWSGI、Apache mod_wsgi等。另外,很多框架本身也提供了WSGI容器,比如:Gevent、Tornado、Twisted。其中,Gunicorn可以通过自定义worker_class搭载其他异步框架来提高性能,比如:Gevent、Tornado、Meinheld等,且容器中运行的也不一定是标准的WSGI应用,比如Gunicorn+Sanic。
ASGI(异步服务网关接口)接口支持Websocket和HTTP/2协议,由Django开发团队提出。支持ASGI的容器不多,貌似只有uvicorn。而支持ASGI应用的框架似乎也只有Django Channels和API Star。另外需要指出,ASGI名称中的“异步”是指网关接口支持异步消息,而并非指ASGI应用的代码是异步的。事实上,Django Channels仍然是传统的非异步框架,其中异步消息推送需要通过Redis作为backend来实现。关于ASGI的更多信息可以查看: https://yoongkang.com/blog/writing-an-asgi-web-framework/
独立部署的应用框架通常是异步IO框架,这些框架因其异步特性,并不兼容WSGI接口。比如:Tornado、Vibora和Japronto。Tornado框架虽然也可以作为WSGI应用运行,但是会失去异步特性。
此外,一些异步框架,比如:Gevent和Meinheld,由于支持monkey patch,可以无侵入地将同步代码以异步的方式运行,所以可以无需独立部署而支持WSGI应用。
下表是代表性的异步框架,以及框架采用的事件循环库:
- uvloop(sanic,japronto,vibora)
- picoev(meinheld)
- asyncio(tornado 6+)
- libuv/libev(gevent)
- libevent(eventlet)
早期版本的Tornado采用自己实现的事件循环(Linux系统下基于epoll、BSD系统下基于kqueue、Windows系统下基于select模型),性能并不是很高。
至于CGI/FastCGI模式,由于性能低下,几乎已经淘汰,不再做讨论。
如果采用WSGI框架,那么推荐使用Gunicorn+Meinheld。这个组合经过大量测试证明了其优越的性能;如果选择Django,那么只有Django+Channels+uvicorn一种选择;如果要构建API后台,推荐Falcon和API Star;异步框架里相对成熟可靠的就是Tornado和Gevent,Sanic、Japronto和Vibora,这三个后起之秀虽然性能了得,但是Sanic有各种BUG,易于崩溃,Japronto已经停止开发了,Vibora属于个人项目,已经很久没有更新了。
另外,前两年很火的Flask越来越感觉鸡肋了。性能平庸,配套也不完整,还不如Django、Pyramid等成熟的全家桶。
至于异步模式下各种数据库驱动,大致有两种解决方案:一是纯python驱动,使用monkey patch来支持异步;另一种是使用aio版本的驱动。对于某些底层使用native编译的驱动,如mysqldb,就无法改成异步模式了。