Python 的 async 协程当前真的能跑在生产环境吗?

18 天前
 wudanyang

python async 启动协程时,如果当前协程不主动 await 释放,那就会一直占用事件循环,其他协程无法执行。

能想到的一些非常有风险的点:

  1. 程序员忘了写 await ,单纯靠 cr 很难完全发现,导致阻塞
  2. python 第三方库没有做 async 改造,不小心用了,导致阻塞
  3. 有可能本地运行时间短,到了线上数据量大了,阻塞时间变长

问了 ds 和 chatgpt , 看起来都没有很好的解决方案

5938 次点击
所在节点    Python
73 条回复
pursuer
18 天前
第一条 python 的 await 如果写漏了,协程是不会运行的,第二条没改造的第三方库可以丢给其他线程跑,第三条和数据量大用不用协程都存在的一样的问题
chenqh
18 天前
可以跑,阻塞就阻塞,你用 supervisor 多起几个进程就行了.虽然这种情况下有没有 async 都一样了.
wudanyang
18 天前
@pursuer #1 第一条的意思是,程序员写了一个执行时间长的语句,但是中间没有使用 await 让出执行。
第二条确实可以放到线程执行,但 python 现在异步生态没这么好,很多都需要线程执行了
第三条如果直接用线程的话,线程是抢占式调度,不会让一个线程一直占着 cpu ,但是协程遇到数据量增长的情况,占用的 cpu 就会越来越多
wudanyang
18 天前
@chenqh #2 如果启动的是 web server ,同时来两个请求,耗时本来都很短。
这时候如果其中一个请求阻塞了,那另一个请求的耗时也跟着变长了。
yh7gdiaYW
18 天前
第二点是巨坑,光靠 review 很难 100%发现,只能结合压测以及多开一点 worker 进程了
pursuer
18 天前
@wudanyang 协程的作用就是协作执行,执行时间长(我假设说的 CPU 密集)还需要自动让出,那就是多线程的场景。实际多线程要考虑锁和线程安全,写线程安全代码未必比手动 await 简单。python 的线程是抢占式调度,但这个和协程无关,无论多少协程也都是跑在这个可以抢占调度的线程上的。
wyntalgeer
18 天前
内容跟标题没有丁点关系,看不出 async 为什么不能跑生产

人菜跟工具有什么关系,内容好似在问给 3 岁小孩玩菜刀一样
lasuar
18 天前
asyncio.to_thread() 用于处理同步函数。
unused
18 天前
没人规定用了协程就不能多线程了
wudanyang
18 天前
@wyntalgeer #7 看不出来吗?表达的是容易阻塞事件循环,导致线上延迟甚至挂掉
wudanyang
18 天前
@unused #9 问题是就算是混用,其中协程的部分也容易出现上面的问题,导致阻塞
chenqh
18 天前
@wudanyang 这个倒是确实会.但是你可以多开一些进程啊.把 async 把阻塞用吧,虽然理论不行,但是呢又不是不能用.
chenqh
18 天前
@wudanyang 我现在倒是觉得 python web 根本没有必要多线程,async/await 直接多进程走起,反正 linux 进程和线程的区别又不大,除非你起个上百个进程,估计影响不大,而且我也没有搜到, 开上百个进程与上百个线程之间的性能差距到底有多大,延迟有多高.
chenqh
18 天前
@chenqh 以前只是知道多线程比多进程性能,但是啊,差距有多少?没有人说啊.我现在都不明白我当时为什么会因为仅仅
好而去选择呢.
capric
18 天前
3.7 就开始用在生产环境了,哪有什么大坑,稳的很
fds
18 天前
那么多人都在用……当然新手用不好也正常。卡主线程是很常见的 需要注意的问题,用 nodejs 也一样。你多写点测试看看阻塞没阻塞呗。
当然 python async 历史比较久,实现也多种多样,建议多读读官方文档
https://docs.python.org/3/library/asyncio-task.html#running-in-threads

你要接受不了不如换 go ,异步流程更清晰,性能也更好。当然处理 json 什么的就麻烦些。
Vegetable
18 天前
1. 你不 await ,函数不会执行,不存在阻塞的情况。
2. 三方库每做 async 改造,不小心用了——这种情况令人难以置信,需要关注几乎就只有 io 一种场景。常用的操作都有专门的异步版本,很难想象这个场景有什么“不小心”。
3. 不理解
fds
18 天前
o 对 忘了说了,如果你要用 python 做 web ,那无论如何是不能放 cpu 密集的任务的,因为放在哪里都会卡住。这种还是找个任务队列或者就先临时存在数据库里,然后再另外启动一些后端服务处理。
w568w
18 天前
我总结你说的三点,其实都是一个问题:单线程的协程模型是否会被 内在(本身写的同步代码太复杂)或外在(调用了阻塞的第三方库)的 CPU 密集过程卡住事件循环?

答案是有可能,并且我遇到过不止一次了。

对策也是三个:

1. 取决于你 asyncio 的实现,是可以开多个 worker 线程进行池化调度的。并不是所有实现都是真的「单线程」。有一些高级运行时还有 work-stealing 之类的机制帮助多线程调度;

2. 人工检查可能卡住的地方,繁重任务放到新线程去做;

3. web 这种可能涉及高并发的情况,如果担心此类问题,还是用线程模型的框架较好。
111111111111
18 天前
1. 协程才可以被 await ,而且必须要被 await ,否则会引发警告,并且不会阻塞,而是继续执行下一行代码

2. 异步代码里“写”或“调用”同步代码,这二者没区别,这个阻塞是预期内的,所以写代码(或选第三方库)的时候想清楚要同步、异步、还是混写,以及哪种异步

3. await 主要是用在 IO 时切换,就算数据多等待的时间长,但是不影响其他协程的运行,也不吃 CPU ,时间长就长呗,有啥好担心的


OP 提到确实是使用 aync 该要思考的,其实更多和人有关,而不是和 async 的设计有关

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/1140935

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX