Python技术迷

再见多线程!这几个 Python 库快得不可思议

唉我跟你说啊…昨天半夜一点多,我在客厅那边喝着冷掉的咖啡,本来还想早点睡的,结果群里有人又问我“东哥 Python 多线程是不是快不了啊,有没有啥更猛的库”…我脑子里嗡一下,又开始给他们讲,顺便我就在这儿跟你们也唠唠,反正都打字了…你等下我先把杯子挪一下…好了好了继续说。

asyncio 这家伙是真能打

我当时就在沙发那边比划着跟他们说,Python 那个 GIL 啊…就是那种你看着很烦但又砸不掉的锁。所以 CPU 任务用多线程基本白搭,但是 IO 嘛…哎你们懂的,就是等数据、等网络、等磁盘的那些,它就特别适合 asyncio。

我前阵子给公司做一个批量抓取接口数据的脚本,就是用 asyncio 写的,速度快到夸张,是之前多线程版本的七八倍。当时我还在电脑前“卧槽”了一声,吓我家猫都跳起来了。

随便给你丢段代码,你看着就知道结构特别清爽:

import asyncio
import aiohttp

asyncdeffetch(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 Pool

defwork(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 ThreadPoolExecutor

deftask(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 asyncio

uvloop.install()
# 后面还是你原来的 asyncio 代码

就…很离谱。

Trio:写起来舒服得不得了

Trio 这个库吧,我是去年国庆在火车上无聊玩出来的。语法特别温柔,你感觉它就不像 Python 官方写的,“不像库的库”。性能也不差,就是生态没有 asyncio 那么全。

不过像我那天在动车上写网络测速脚本,用 Trio 写得贼顺:

import trio
import httpx

asyncdeffetch(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