你必须要会uvloop!让Python asyncio异步编程性能直逼Go协程性能
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情。
背景
我之前开发《联机桌游合集》时,使用到了WebSocket协议,后端我是用Python实现的,我使用了Python的一个库:daphne。daphne是基于python原生asyncio的库。
最近我在思考后端优化的事情,了解到了uvloop,它是python原生asyncio事件循环的替代品。
先介绍下asyncio
Python从3.4开始,引入了asyncio
库,参考PEP-3156。Python从3.5开始,引入了async
和await
语法,参考PEP-0492。
Python中的用法其实跟javascript中的async
和await
相似,毕竟脚本语言的规范,基本都是抄来抄去,都愿意把隔壁语言的优秀语法吸纳进来。这对开发者也很爽,更容易学另一门语言了。
Python3.4和3.5算是推动了一场革命,自此,Python异步编程越来越火(基于协程)。
也许你不懂协程,我简单介绍下:
以前我们用Python写爬虫,可能会用
requests
这个库,requests.get(url)
发请求,等到有了结果,代码再继续进行下去。它是顺序的同步的执行。当请求发生时,你只能傻傻的等,不能让代码去做另一件事。除非你新开一个线程去做另一件事。但是现在,我们有了异步编程。基于内置的事件循环,我们可以达到这样的效果:遇到I/O操作(例如Http请求)时,我们先暂停这段代码(这个任务)的执行,再去看看有没有其它任务可以执行,如果有其它任务可执行,就执行其它任务。如果所有任务都无法执行,就等着,直到有1个任务可执行了,就执行它,直到它运行完毕或者遇到I/O操作,再暂停它,执行其它任务。
注意,Python中的异步编程,是基于事件循环的。今天,我们要聊的就是事件循环。
关于uvloop
uvloop
是Python原生事件循环的替代品。提高了性能。
为什么提高了性能
(说法来源于uvloop官方博客)
- uvloop是基于Cython写的,执行效率更高。
- uvloop底层基于
libuv
,而libuv
是高性能、跨平台的异步IO库,nodejs的事件循环也是基于libuv
的。
Benchmarks
这不是我做的,我只是转发一下uvloop官方测试结果。
分为两种测试:TCP协议和HTTP协议。
TCP
这是用简单的echo服务做的测试,不能代表所有生产环境的情况。
分别用1KiB数据包、10KiB、100KiB做了测试。
可以看到uvloop确实牛逼,性能直逼Go。
HTTP
解释下:官方人员本来想用aiohttp
这个Python中最常用的异步http服务库测试的。但是它的http解析器效率太低了,已然成为整个系统的瓶颈,所以他们手动实现了http-parser
(起初是为Nginx设计的,所以效率非常高)的Python版本,称之为httptools
。
可以看到,asyncio原生事件循环和uvloop,对aiohttp没有性能提升!(看完后,我想:以后不敢用aiohttp了)
而把http解析器这个瓶颈解决掉后,asyncio原生事件循环和uvloop性能都明显提升,但uvloop明显更牛逼,在10KiB和100KiB场景下,性能超越了Go。
uvloop有缺点吗
有,不支持Windows。
怎么使用uvloop
安装
shell
pip install uvloop
引入
python
import asyncio
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
其它async代码不变,你就享受到了更快的事件循环!
感受
如果一味追求性能,还是直接用Go吧。
但是uvloop确实给Python开发者提供了更强的性能,对于Python开发者很爽。但是也要注意,有没有其它性能瓶颈,例如跟aiohttp结合使用时,瓶颈可能在于http解析。
参考博客:uvloop: Blazing fast Python networking
写在最后
我是HullQin,独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋、UNO等游戏,绝不收费,绝无广告,点这就能开始玩。还独立开发了《合成大西瓜重制版》。喜欢可以关注我噢~我有空了会分享做游戏的相关技术,会在这2个专栏里分享:《教你做小游戏》、《极致用户体验》。
- 在互联网,摸爬滚打了几年,我悟了。面对如今经济形势,普通打工人如何应对?
- [Go WebSocket] 你的第二个Go WebSocket服务: 聊天室
- 我们用48h,合作创造了一款Web游戏:Dice Crush,参加国际赛事
- [JS真好玩] 掘金前端你好:作者榜出bug啦,我们一起看怎么修。顺便分享创意技巧:改EventListener
- [教你做小游戏] 展示斗地主扑克牌,支持按出牌规则排序!支持按大小排序!
- [JS入门到进阶] 手写裁剪图片的工具,并部署。一键裁剪掘金文章封面
- [JS入门到进阶] 手写解析URL参数的工具,并部署。用起来又快又爽!
- 你必须要会uvloop!让Python asyncio异步编程性能直逼Go协程性能
- [JS入门到进阶] 7条关于 async await 的使用口诀,新学 async await?背10遍,以后要考!快收藏
- [JS真好玩] 大招!用JS找到:哪 个 小 坏 蛋 给 我 连 点 2 次 赞 ?
- [JS真好玩] 掘金创作者必备: 监控每天是谁取关了你?
- [极致用户体验] 用transform后z-index失效了?总结transform的注意事项!
- [极致用户体验] 我又来帮掘金修专栏bug了,顺便教你个超牛逼的分割线CSS!
- 《 合 成 大 西 瓜 》 重 制 版 !( 联 机 版 在 做 了 )
- [教你做小游戏] 用86行代码写一个联机五子棋WebSocket后端
- [JS真好玩] 我帮掘金找到了一个小Bug,可利用该Bug增加专栏粉丝数
- [JS真好玩] 表格不支持排序?用4行JS排序!两种方案:基于flex order或replaceChildren
- [JS真好玩] 嘘!我改了掘金源代码!1行代码,让表格支持page_size切换,从每页10条变为20条!
- [教你做小游戏] 《五子棋》怎么判断输赢?你能5分钟交出代码吗?
- [极致用户体验] 让你做个《五子棋》怎么存储棋盘上的棋子信息?