AberSheeran
Aber Sheeran

加速Python的asyncio

起笔自
所属文集: 程序杂记
共计 1523 个字符
落笔于

Python的asyncio模块带来了语言本身的异步功能,不再需要gevent之类的猴子补丁。但速度上,asyncio有点慢。

不过这个库设计之初,就允许了使用自定义的loop代替默认loop。这给更好的性能,带来了可能。

非 Windows

libuv 是一个跨平台的,高性能异步IO库。Node.js被人吹鼓的性能,一半的功劳来自于它。

于是有大佬以它为基础,用Cython写了uvloop,使用的时候只需要两行代码就可以使用性能更好的loop代替原生asyncio默认loop。

import uvloop
uvloop.install()

遗憾的是,由于大佬们很久没用过Windows,并不想自己写Windows的代码。有其他人试图贡献Windows上的代码,但遇到了困难。所以从2016年至今,Windows支持仍然只是uvloop的可行方向,并没有真实可用的代码。

Windows

那么,Windows上真的没有优化途径了吗?答案显然是有。

众所周知,Windows上的IOCP是一种真正的异步IO,它比默认的select性能更佳,libuv在Windows上使用的也是IOCP。

Python的asyncio库自诞生以来,其实就支持IOCP loop,可以调用asyncio.ProactorEventLoop()去创建一个IOCP loop。

在3.7的版本里,asyncio标准库里增加了asyncio.WindowsProactorEventLoopPolicy

所以在Windows上使用IOCP进行优化的代码应该如下:

import sys
import asyncio

if sys.platform == 'win32':
    if sys.version_info.major >= 3 and sys.version_info.minor >= 7:
        asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
    else:
        asyncio.set_event_loop(asyncio.ProactorEventLoop())

这样,ProactorEventLoop就会代替默认的SelectorEventLoop,从而在Windows上有更好的性能。

而在Python3.8中,asyncio在Windows上已经开始使用默认IOCP了。Python Document

统一代码

那么结合以上两种代码,可以得出一个复制粘贴即可使用的代码。

if sys.platform == 'win32': # use IOCP in windows
    if sys.version_info.major >= 3 and sys.version_info.minor >= 7:
        asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
    else:
        asyncio.set_event_loop(asyncio.ProactorEventLoop())
else: # try to use uvloop
    try:
        import uvloop
        uvloop.install()
    except ImportError:
        pass
如果你觉得本文值得,不妨赏杯茶
Python的元类
os.system在Docker中的坑