问一个协程方面的问题

2021-12-13 15:04:45 +08:00
 kingofzihua

协程究竟解决了什么问题,都在吹协程,像是 go 、kotlin 都有协程,java 本身没有协程,

还有相比于线程,协程的优势是什么,为啥 java 没有协程,性能框架和 go 框架不相上下,协程这么牛逼为啥 rust 没有内置协程(听说都已经写好了,但是不符合理念,没合并)

操作系统调度的时候是以线程为单位调度的,又不知道协程的存在,即使你用协程了,操作系统还是只知道你是线程啊。

各种博客,都只说了比线程更轻量,占用内存小,切换成本小,但是线程切换是操作系统决定的,系统切换线程,你协程也没用啊。

各位大佬,救救孩子吧。

12891 次点击
所在节点    Linux
155 条回复
whoosy
2021-12-13 15:31:48 +08:00
线程进程切换涉及到内核调度,也就是要从用户态切换回内核态,切换有成本,比如虚拟内存、堆栈的切换。
协程不被操作系统感知,协程切换完全由程序控制,切换成本忽略不计。
coldear
2021-12-13 15:40:15 +08:00
别的语言不清楚,kotlin coroutuine 实际就是 callback ,最终执行的时候,就是线程池在执行不同的 callback ,
一个 coroutine 有一些 local 的状态,只需要一点点内存就可以存储,不需要 stack 之类,比线程要轻量。
多个 coroutine 可以在一个或者几个线程上执行,所以 context switch 要少很多。
不过也没有什么魔法,该 block 的地方还得 block , 只不过 coroutine 内存占用很小,可以创建非常多,一般不用考虑资源限制,这样不用写各种资源管理的代码,让代码看上去更简单。
liyixin95
2021-12-13 15:44:42 +08:00
rust 移除内置协程的原因是其不符合零开销抽象原则,何为零开销抽象:
1. 如果你不需要这个功能,你就不用为这个功能付出代价
2. 如果你需要这个功能,你没法写出开销更小的代码

协程需要自带一个 runtime ,这对不需要协程的用户来说就违背了第一条原则,故移除掉了。
learningman
2021-12-13 15:46:58 +08:00
比如说,一次 IO 请求,延迟是 300ms ,但是发出请求 1ms 就够了,这就是典型的协程的应用场景。
不然你应该怎么做?开一个线程,挂起等返回?这是操作系统切换的,太重了,协程轻的多也快的多
kingofzihua
2021-12-13 15:52:17 +08:00
@learningman 这个例子感觉举得不太好,或者我没理解你说的,java 没有 协程,NIO 一样能高吞吐!并且也没有一次 IO 就挂起。也不需要线程切换,不然 java 早就被淘汰了
documentzhangx66
2021-12-13 15:52:59 +08:00
1.我们只需要 CPU 运行我们自己写的代码,尽可能少的运行别的代码。

2.协程或纤程 = 我们写的代码 + 尽可能少的程序框架的管理代码

3.线程 = 协程或纤程 + 操作系统的一小部分管理代码

4.进程 = 线程 + 操作系统的一大部分管理代码

如果这样说,你还不明白,再举个例子:

协程或纤程 = 你自己想喝水,你步行 2 分钟,花 2 元买了一瓶农夫山泉。

线程 = 你叫了美团,花了 3 元农夫山泉 + 1 元配送分 + 等候 20 分钟。

进程 = 你上淘宝,花了 3 元农夫山泉 + 10 元快递费 + 等候 3 天 + 花了 10 分钟走路去菜鸟驿站取回。
Edsie
2021-12-13 15:58:41 +08:00
楼主了解下线程切换的开销问题

#4 kingofzihua 我一个线程内为啥要进行多个协程切换?
如果你只有一个线程的话,那就不是多线程问题了

还有,NIO 高吞吐实现,是基于 IO 多路复用,跟这个不是一回事。
hguandl
2021-12-13 15:59:36 +08:00
你自己也说了“如果不是系统阻塞,那我完全可以在线程内执行其他的,后面再回来执行”。其实协程就是对你这种做法的抽象,通过生命周期和上下文来更轻松地控制调度。这和你直接在线程内做非阻塞 IO 没有本质区别。协程的思想可以降低写非阻塞程序时的心智负担,提高可读性、降低出错的可能。
fkdtz
2021-12-13 16:02:04 +08:00
首先提这样一个问题:“多线程已经能够实现并行执行了,为什么还要协程?”。

用一句话解释就是协程的效率比线程更高。

因为协程是在用户态模拟操作系统对线程调度的过程,协程编程中常见的关键字 yield ,在操作系统中也有原型:yield() 函数。

这就省去了操作系统在上下文切换时产生的额外的寄存器的读写,充分利用单核 CPU 计算能力。

所以想要理解协程,可以参考操作系统对 CPU 的虚拟化和对线程的调度过程,尤其是当发生中断时(如发生 IO 事件时),操作系统如何调度,协程与之十分相似。
ipwx
2021-12-13 16:03:24 +08:00
“如果阻塞是系统调用阻塞,线程就会挂起,调度到其他的线程了,你协程没用”

所以协程要配合非阻塞 IO 。

原先 callback 或者 Future.map 就是非阻塞的,但是写起来心智负担太大。所以抽象了一种 IO ,形式上是阻塞的,但是实质上是非阻塞的。await non-blocking read 会把控制流立刻转向其他协程,而当这个 non-blocking read 成功以后这个协程会重新进入调度队列。
MakHoCheung
2021-12-13 16:06:46 +08:00
我来通俗发表一下我的观点,协程其实就是并发编程的一种语法糖,它可以让线程执行到某行代码(比如 HTTP 请求)后停下来不再继续执行下面处理返回的代码,反而去跑其他的代码。为什么要这样做呢,因为可以让线程无时无刻在运行代码,不会因为等待 IO 阻塞而空闲着,比如 IO 多路复用就可以循环查询 IO 事件,没有查到就去执行队列的任务。如果不用协程的话,完全可以基于 NIO 的 IO 多路复用实现 EventLoop 充分利用线程去工作。只是 Java 没有这种语法糖而已。简单一句就是以前 IO 读阻塞、写阻塞等阻塞导致线程挂起空闲,现在可以让线程在遇到读阻塞和写阻塞的时候去执行其他任务。
ipwx
2021-12-13 16:08:47 +08:00
并发种类:

1. 多线程:太慢

2. callback:代表作为 Node.js 、python tornado ,boost asio 。但是会陷入 callback 地狱。

3. Promise / Future:java, scala, js, 比 callback 好多了,目前是主流技术之一。缺点是要仔细管理闭包的嵌套。

4. event loop:一般 c/c++ libev libuv ,还有 python gevent 。心智负担比上述三种都大,但是可以更精细操作、更高效。底层实现一般为 kqueue 和 linux 上的 epoll ,或者 fallback 到 select 。

大名鼎鼎 nginx 就靠 event loop 暴打同时代。

5. 协程。

协程一般用 event loop 实现,这种协程就是对 event loop 的抽象。要理解协程,建议稍微学习一下 event loop 。
ipwx
2021-12-13 16:10:07 +08:00
其实这里有两条技术路线

callback => promise / future
event loop => coroutine

要理解协程就要去理解这两条技术路线的区别。
momocraft
2021-12-13 16:10:13 +08:00
> 如果不是系统阻塞,那我完全可以在线程内执行其他的,后面再回来执行
这个听起来就挺像协程
0o0o0o0
2021-12-13 16:10:23 +08:00
@ipwx 补一个 async/await ,不过实现方法有很多
MakHoCheung
2021-12-13 16:10:41 +08:00
普通的 Java 利用到线程池的并发编程都可以做到协程的性能,只是写起来后者更轻松
cloverzrg2
2021-12-13 16:11:16 +08:00
CPU 密集型:用线程,线程数为 cpu 核心数
IO 密集型:用协程,一个请求起一个协程
ch2
2021-12-13 16:13:31 +08:00
@kingofzihua #17 "你如果用协程,系统调用还是操作系统给你切换到其他线程了",非阻塞 IO 模式下线程可以批量获取一大堆文件 /网络套接字的读取结果,协程可以按阻塞 IO 的编程方式写出来非阻塞 IO 模式下不需要频繁切换 CPU 的代码的性能
MakHoCheung
2021-12-13 16:16:17 +08:00
“阻塞是系统调用阻塞,线程就会挂起”,重点就这里了,阻塞的时候线程不会挂起(因为 NIO 、IO 多路复用、EventLoop )这可以解答到你的疑惑了
oxromantic
2021-12-13 16:16:49 +08:00
协程一般配套的就是无阻塞模型,再加上没有线程切换,可以最大化压榨性能,从语法上给你同步的体验,性能是 callback 的性能

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

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

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

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

© 2021 V2EX