我来说说异步框架的最大缺点

2021-04-20 16:04:09 +08:00
 balabalaguguji

异步大家都在夸,都在说他的好处,但是似乎没人说过他的最大缺点,我来说说吧,避免踩坑。

异步因为是只有一个线程,如果有一个地方阻塞了,那整个网站全部都卡住了(多进程的另说),所以你得时刻记得,如果会阻塞的方法,就得用异步的库。另外还得确保别写出死循环的逻辑,不然也是卡住整个站。

异步现在支持最好的应该是 nodejs 吧,各种异步库都有,但是 python 的支持就少很多了,如果用 gevent,猴子补丁不能帮你把所有的接口都补成异步的,所以你得清楚什么方法是可以用的,例如 commands 这个就不能用,没打补丁,可以改用 subprocess 。

写异步的代码时得时刻提醒自己以上问题,但是如果用多线程模型,就不用担心这些,如果你的网站不是特别大的访问量,可以使用多线程模型,够简单;如果是需要高并发,有大量用户,可以用异步框架并始终记住不要用阻塞方法。

如果说得不对的地方,请大家指点。

15784 次点击
所在节点    编程
153 条回复
balabalaguguji
2021-04-20 17:43:52 +08:00
@passerbytiny #38 嗯,其他语言我确实不了解,这里可以理解为我说的是 nodejs 做 web 服务端
balabalaguguji
2021-04-20 17:44:24 +08:00
@tairan2006 #40 nodejs 也是
balabalaguguji
2021-04-20 17:45:07 +08:00
@aper #39 跟我表达的其实是一个意思吧
TypeError
2021-04-20 17:46:38 +08:00
@balabalaguguji #34
“异步因为是只有一个线程”

python 就算是 tornado 也可以配合 concurrent.futures 多线程 /多进程
aper
2021-04-20 17:47:43 +08:00
@balabalaguguji 要求没有多线程同步高,只是后面都是 callback hell,贼恶心。而且不能有很重的 task,要不然很容易挂
balabalaguguji
2021-04-20 17:53:04 +08:00
@TypeError #44 感谢指点,我确实没了解到
Wincer
2021-04-20 17:53:26 +08:00
Python 即使采用同步框架( Flask 等),在视图函数内也可以使用异步操作(请求多个数据库之类的),我司就是这么做的,不过会有一些坑。所以这俩也不是对立面,只不过现在大多数人把异步当成多线程的替代品了。
libook
2021-04-20 18:02:06 +08:00
异步是个流程上的通用概念,不同技术栈的异步实现可能会有区别。

个人认为,异步最大的优势是可以让机器一直干活,不会因为一个未返回的结果而干等;
异步的缺点就是运行时机不确定,两个同时执行的异步过程中的操作不一定谁先谁后,所以如果多个异步过程对同一存储空间执行写操作的的话,每次读这个空间可能得到的值会不一样,多数需求场景下这就是个脏数据。

所以为了避免运行时机的不确定所带来的预期之外的行为,我们有可能得把外层很多原本就可以正常工作的同步代码改写成异步代码,最坏的情况就是要把整个项目所有的代码都写成异步代码。这算是异步间接带来的成本吧,不过一些语言在这方面做了些优化尽量降低开发者的头痛程度,使得不需要增加多少开发成本就可以享受异步红利。

一些需求场景中,工作可以拆分成几部分,而每项工作之间没有严格的依赖关系,在这些场景中用异步就是非常合适的,比如多数互联网应用。
但每项工作之间有严格的依赖关系的话,就不能用异步了,比如算斐波那契数列,每一次计算都依赖上一次计算的结果。

异步与多线 /进程是两个维度上的概念,同步异步是流程概念,线 /进程是操作系统资源调度上的概念(这个和多核、超线程等硬件技术也不是一个维度上的概念),比如我向操作系统申请了 2 个线 /进程,也是可以让线 /进程 1 先执行,执行完返回结果后再让线 /进程 2 执行,这个也可以称作为同步过程。当然通常我们开多个线 /进程就是为了让它们能够同时运行,以成倍地提高计算效率,所以可以说我们大多数用线 /进程的场景都是会采用异步实现的。

没有银弹,不同技术有不同的特性,架构选型的实质就是找最适合当前需求的技术。
Muninn
2021-04-20 18:03:05 +08:00
从 python 转投 golang 之后再也没有这些烦恼了……
cyrbuzz
2021-04-20 18:06:07 +08:00
个人理解= =。

异步模式不是把同步的代码异步化,而是那段代码本身就是一个异步的 IO 。

想把一段代码异步化,得先知道这段代码能不能异步,比如

```
a += 1
```

是一段不能异步的代码。

而一个网络请求则一般都会提供 阻塞和非阻塞 两种模式:

```
http({
async: true(false)
})
```
这样的配合事件循环就可以做到异步。

在 Python 中,像是`requests`是一个阻塞的网络请求,它并没有提供非阻塞的参数,无法直接用类似线程的`async(requests.get, xxxx)`这样的方式去将它异步化,而是应该在底层 socket 建立连接时就使用非阻塞的模式,交由异步的事件循环在这条 socket 等待响应的这段时间去干别的事。

按楼主的举例,commands 是一个阻塞的命令行,确实想用异步应该寻找的是一个非阻塞的命令行而不是想着有一个函数可以把 commands 异步化(事实上 Python 也有,`asyncio.base_event.run_in_executor`函数可以让传入的同步函数放在一个线程 /进程池中执行,同时外部还可以继续用异步的 async/await 或者回调)。

而在 Js 中,如果你在主线程中执行一段一直会占用 CPU 的代码(while(1){})也会阻塞住整个页面。

异步主要是用来解决 I/O 密集的问题的,I/O 所花的时间主要在网络读写,硬盘读写等。

如果一段代码的主要消耗的是 CPU,用异步并不是一个好选择而是应该尽可能榨干 CPU 的性能,衍生出来的就是线程(协程)/进程。

所以在 Python 这个啥程都有的语言里...

在主要是 I/O 的场景里,用非阻塞的库上异步绝对是一个性价比高的选项,其他程切换的开销再小也有开销。
在主要是计算的场景里,多跑几个 Python 进程比啥都管用。

访问量不大的网站用什么根本无所谓...数据量够小的情况下,选择排序和快排根本看不出差别。
balabalaguguji
2021-04-20 18:13:09 +08:00
@libook #48 感谢科普,学习了。
balabalaguguji
2021-04-20 18:14:11 +08:00
@Muninn #49 我也是 python,学习了下 nodejs,感觉想转,异步写起来爽很多。听你这么说,golang 更爽。
rahuahua
2021-04-20 18:16:02 +08:00
多线程异步不香吗?
balabalaguguji
2021-04-20 18:17:50 +08:00
@cyrbuzz #50 感谢科普,个人觉得 python 写异步太麻烦了,nodejs 方便好多。
balabalaguguji
2021-04-20 18:19:24 +08:00
@rahuahua #53 两个结合是挺好,还没了解过具体怎么做,不过按我的了解 nodejs 是只有一个主线程的,没法创建线程。
balabalaguguji
2021-04-20 18:19:58 +08:00
@Muninn #49 可以科普下 golang 怎么个爽吗
rahuahua
2021-04-20 18:22:22 +08:00
@balabalaguguji 网络并发这块没有比 Go 更香的了。完全不用考虑同步异步,所有的网络 I/O 都是同步代码、异步执行,async/await 都不用写
shyling
2021-04-20 18:26:18 +08:00
node, go 都是从一开始都支持。。。相比 python 从同步到异步,就少了很多坑
rahuahua
2021-04-20 18:27:14 +08:00
@balabalaguguji 某位大佬(好像就是 node 之父)说过跟 Go 相比,NodeJS 并发就是个玩具 😃
crclz
2021-04-20 18:27:44 +08:00
“异步现在支持最好的应该是 nodejs 吧”

nodejs 对异步的支持的确挺好,但别忘了 async/await 的爹是谁——C#。C#对于异步的支持一如既往的走在编程语言的最前列。
---

“所以你得时刻记得,如果会阻塞的方法,就得用异步的库”

C#也存在误用阻塞代码会让性能大幅下降的问题,但是这个问题可以从包管理器(nuget)安装检测这种错误的(代码提示)包来终结此类缺陷。
---

“如果你的网站不是特别大的访问量,可以使用多线程模型,够简单;如果是需要高并发,有大量用户,可以用异步框架并始终记住不要用阻塞方法”

据我所知,C#的 Asp.NetCore 可以无缝地切换。Controller 可以拥有同步和异步的方法,不冲突。另外,如果某个年代久远的库只提供同步调用,我们只需讲 Controller 的这个方法写成同步方法即可。

(整体上来说,对于 java 这类编程语言,从简化开发、减少 bug 上来说,楼主的观点是没有错的)

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

https://www.v2ex.com/t/771935

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

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

© 2021 V2EX