再见多线程!这几个 Python 库快得不可思议
唉我跟你说啊…昨天半夜一点多,我在客厅那边喝着冷掉的咖啡,本来还想早点睡的,结果群里有人又问我“东哥 Python 多线程是不是快不了啊,有没有啥更猛的库”…我脑子里嗡一下,又开始给他们讲,顺便我就在这儿跟你们也唠唠,反正都打字了…你等下我先把杯子挪一下…好了好了继续说。
asyncio 这家伙是真能打
我当时就在沙发那边比划着跟他们说,Python 那个 GIL 啊…就是那种你看着很烦但又砸不掉的锁。所以 CPU 任务用多线程基本白搭,但是 IO 嘛…哎你们懂的,就是等数据、等网络、等磁盘的那些,它就特别适合 asyncio。
我前阵子给公司做一个批量抓取接口数据的脚本,就是用 asyncio 写的,速度快到夸张,是之前多线程版本的七八倍。当时我还在电脑前“卧槽”了一声,吓我家猫都跳起来了。
随便给你丢段代码,你看着就知道结构特别清爽:
import asyncio
import aiohttpasyncdeffetch(session, url):
asyncwith session.get(url) as resp:
returnawait resp.text()
asyncdefmain():
urls = ["https://example.com"] * 50
asyncwith aiohttp.ClientSession() as session:
tasks = [fetch(session, u) for u in urls]
results = await asyncio.gather(*tasks)
print(len(results))
asyncio.run(main())
你用线程池跑这玩意?肯定没他快。
multiprocessing:真要算力就靠它
我上周在公司楼下抽烟的时候,小李跟我吐槽说他写的图像处理脚本慢得要死。我看了一眼他用 threading,那还不是废嘛…我跟他说你要 CPU 任务,就别想多线程了,你直接 multiprocessing,让 Python 给你开进程,多核全用上,飞起。
他后来改了之后激动地说快了十倍。其实代码也就那个样子:
from multiprocessing import Pooldefwork(x):
return x * x
if __name__ == "__main__":
with Pool() as p:
print(p.map(work, range(1000000)))
我跟他说:“你这玩意不但快,而且是真正的并行,不像线程那种假装忙的。”
concurrent.futures:拿来就用,不想动脑的时候首选
有时候我加班到脑袋懵的时候,我就懒得写这些协程啊进程池啊,直接用 concurrent.futures,那种“你别问,能跑就行”的状态你知道吧。
线程池就这么用:
from concurrent.futures import ThreadPoolExecutordeftask(n):
return n * 2
with ThreadPoolExecutor() as ex:
r = list(ex.map(task, range(20)))
print(r)
进程池换个类名就完事。非常适合那种晚上十一点等外卖又赶脚本的时候。
uvloop:asyncio 的外挂加速器
还有一次周末在家修路由器,我突然想到我们后端接口压测那个服务是不是可以用 uvloop 提速,结果随手一改,直接 2 倍速。我当时都笑出来了,感觉像是 Python 给我加了个涡轮增压。
你只需要加上:
import uvloop
import asynciouvloop.install()
# 后面还是你原来的 asyncio 代码
就…很离谱。
Trio:写起来舒服得不得了
Trio 这个库吧,我是去年国庆在火车上无聊玩出来的。语法特别温柔,你感觉它就不像 Python 官方写的,“不像库的库”。性能也不差,就是生态没有 asyncio 那么全。
不过像我那天在动车上写网络测速脚本,用 Trio 写得贼顺:
import trio
import httpxasyncdeffetch(url):
asyncwith httpx.AsyncClient() as client:
r = await client.get(url)
return r.text
asyncdefmain():
asyncwith trio.open_nursery() as n:
for _ in range(30):
n.start_soon(fetch, "https://example.com")
trio.run(main)
写着写着还差点睡着…旁边的人以为我被代码熏晕了。
我说了这么多,反正意思就是 Python 多线程这东西别再迷恋了,能用协程就协程,真要跑 CPU 就用进程池,懒就用 futures,想加速就上 uvloop。
哎算了我不说了,我这边外卖到了,我先去拿一下…你要是想让我再展开讲哪个库你就喊我一声哈。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB