Python asyncio 中怎么执行 cpu 密集型任务? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
gosky
V2EX    Python

Python asyncio 中怎么执行 cpu 密集型任务?

  •  
  •   gosky 2024-07-23 12:57:31 +08:00 3955 次点击
    这是一个创建于 511 天前的主题,其中的信息可能已经有所发展或是发生改变。
    理论上讲,两个办法:
    一、多线程,但不知道怎么全局解释锁被优化得怎么样
    二、多进程,消耗更多内存,因为需要加载模型,内存复制必须要考虑。多进程管理是个麻烦,启动耗时也得考虑

    期望有个轻量级的开源程序,轻松完成这个活……
    第 1 条附言    2024-07-23 14:54:15 +08:00
    其中的 cpu 密集型,依赖 python 库
    第 2 条附言    2024-07-24 08:54:54 +08:00
    问了下 ai ,pytorch c 扩展大部分会释放 gil ,于是决定采用多线程的方式
    但……实际运行后,发现虽然自己撸灵活,还是专用推理服务更节省资源
    25 条回复    2024-08-02 10:49:58 +08:00
    changz
        1
    changz  
       2024-07-23 13:04:13 +08:00 via Android
    多线程+c/c++ ffi
    gaogang
        2
    gaogang  
       2024-07-23 13:20:20 +08:00
    cpu 密集的任务 用其他合适的语言实现
    然后通过 rpc 暴露出来 正好给 python 的 asyncio 调
    tf2
        3
    tf2  
       2024-07-23 13:23:53 +08:00   1
    asyncio 顾名思义是 异步 io 。。。众所周知,py 要么卡 cpu 要么卡 io ,asyncio 只解决卡 io 的问题啊。
    ysn2233
        5
    ysn2233  
       2024-07-23 13:32:10 +08:00   1
    用 c/c++/rust 的 ffi 做 binding 吧,实在不行 java/go 什么的也行,python 就做个前端调一下
    mirrornighth
        6
    mirrornighth  
       2024-07-23 13:32:51 +08:00
    多进程
    ipwx
        7
    ipwx  
       2024-07-23 13:34:03 +08:00
    “因为需要加载模型,内存复制必须要考虑。”

    你是啥模型。有些模型开多线程是可以并行的。
    Goooooos
        8
    Goooooos  
       2024-07-23 15:05:21 +08:00
    python 3.13 可以加个参数去掉 GIL
    guochao
        9
    guochao  
       2024-07-23 15:24:16 +08:00
    针对锁和 python 效率的问题:
    - 如果你的计算任务可以用 c/rust 的模块,最好是在 c/rust 的部分处理,最好能批处理
    - 如果是 pure python ,也许可以试试 taichi 或者类似的东西。因为 python 可以被再次编译成 native 或者 gpu kernel ,并针对架构优化
    针对 asyncio 只管异步切换,计算存在长时间阻塞的问题
    - (不同进程、单独服务的方案)要么 celery ,或者自己搓一个简单的队列
    - (简单在同一个进程中的方案)要么 thread pool executor
    itskingname
        10
    itskingname  
       2024-07-23 16:04:22 +08:00
    simple2025
        11
    simple2025  
       2024-07-23 16:17:48 +08:00
    你加载的模型很大吗?不然想不出来为什么不用多进程
    ruanimal
        12
    ruanimal  
       2024-07-23 16:43:54 +08:00
    跑模型还是多进程好
    razertory
        13
    razertory  
       2024-07-23 16:45:46 +08:00
    asyncio 是做 IO 密集任务的,不是做 CPU 密集任务
    scipelaina
        14
    scipelaina  
       2024-07-23 20:07:56 +08:00
    `asyncio.to_thread`; `concurrent.futures`.
    日经问题,Mark as Duplicated.
    wujian752
        15
    wujian752  
       2024-07-23 22:48:26 +08:00 via iPhone
    如果是神经网络模型现在 onnxruntime 在 inference 的时候可以不受 GIL 影响
    crackidz
        16
    crackidz  
       2024-07-23 22:57:16 +08:00
    Python 主要冷启动耗时几十 ms 左右,剩下的交到你的代码中了,启动时间主要取决于你的代码吧...

    上面说的基本差不多了,但现在不推荐用那个 nogil 版本,要改你的代码支持部分功能,第三方库也未见得支持。另外还有一些隐蔽 bug...
    yoiteshaw
        17
    yoiteshaw  
       2024-07-23 23:04:14 +08:00   1
    我工作中遇到过类似的事情,两年前,无论怎么优化都收效甚微,多线程因为 GIL 反而更慢,最后不得已用多进程去做,用 socket 去通信。
    今年我推翻用 rust 重写了,一些逻辑直接的遍历,简简单单 pair_iter 解决,心情舒畅。
    sagaxu
        18
    sagaxu  
       2024-07-23 23:28:18 +08:00
    Python 的 CPU 密集型库大都用 C 实现,大部分时间不会持有 GIL
    skuuhui
        19
    skuuhui  
       2024-07-24 08:42:30 +08:00
    最简单是写个 c++模块,用 python 去调。
    其他方法有
    1. 换个没锁的解释器
    2. wasm
    3. https://numba.pydata.org/https://www.trypyjion.com/
    Nich0la5
        20
    Nich0la5  
       2024-07-24 09:19:55 +08:00
    asyncio 就不是给你做 cpu 密集型用的
    gray0
        21
    gray0  
       2024-07-24 09:21:41 +08:00
    何必多 BB 直接上代码

    from concurrent.futures import ProcessPoolExecutor
    import asyncio

    async def integration_process_and_gather():
    with ProcessPoolExecutor() as process_pool:
    loop = asyncio.get_running_loop()
    numbers = [100000000, 1, 100, 10000, 1000000, 1000, 100000]
    tasks = [
    loop.run_in_executor(process_pool, do_count_number, n) for n in numbers
    ]
    [print(type(task)) for task in tasks]
    results = await asyncio.gather(*tasks)
    print(f"integration_hello_world {results}")
    yh7gdiaYW
        22
    yh7gdiaYW  
       2024-07-24 11:33:34 +08:00
    简单点就多进程,复杂点就上 ray ,可以分布式计算用得很爽
    lttzzlll
        23
    lttzzlll  
       2024-07-25 17:38:07 +08:00
    你提出的问题,限制你的思路。web 服务要简单,轻量,快速响应。推理服务耗时耗资源。正确的方式应该是 同一个项目(git repo),部署多个进程。经典的做法应该是 一个 web 服务进程,多个 worker 进程,web 服务和 worker 进程之间用队列。以 django/flask 举例:
    lttzzlll
        24
    lttzzlll  
       2024-07-25 17:53:54 +08:00
    @lttzzlll 。。。你面的问题不是“Python asyncio 中怎么执行 cpu 密集型任务?”。 换成其他的 web 框架或语言,就没有这种问题了吗?而是在 web 服务中,如何处理比较耗时/耗资源的任务。这些问题都有很经典很成熟的方案。把这类任务放到 worker 节点上,用队列传递消息,不够就增加 replica 的数量。非常成熟和广泛使用的方案,你的场景也不例外。
    cooljiang
        25
    cooljiang  
       2024-08-02 10:49:58 +08:00
    CPU 密集型任务建议换个没 GIL 的 Python 解释器,如 PyPy 之类的。
    关于 GIL: https://mp.weixin.qq.com/s/lIkcTuCX5htQcteklCFaZw
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3212 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 11:46 PVG 19:46 LAX 03:46 JFK 06:46
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86