问一个协程方面的问题

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

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

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

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

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

各位大佬,救救孩子吧。

12982 次点击
所在节点    Linux
155 条回复
xFrye
2021-12-13 17:03:41 +08:00
不考虑协程底层怎么实现的情况下,协程最直观的作用就是把一些需要异步 + callback 的代码以同步的方式表达出来,这样在代码结构上更加直观。同一个线程处理 n 个协程( callback ),切线程总比你这样切 callback 的代价要大
anytk
2021-12-13 17:04:09 +08:00
@kingofzihua 协程的另一个用法是用在插件系统开发中,插件部分是一个小的 context ,但是使用又是受限的,可以由主程序提供多个接口,配合主程序的 eventloop 来实现插件的受限自定义开发工作,降低插件开发的难度要求。
kingofzihua
2021-12-13 17:06:51 +08:00
@misaka19000 好文
codehz
2021-12-13 17:08:35 +08:00
协程就是一种代码的组织结构,你当然可以全部使用手写状态机来做,事实上早期开发大部分都是这个模型。。。
作为一种结构,它可以大幅度简化某些场景的代码复杂度,这就是它最初的意义。
即使传统磁盘 IO 没办法使用 poll 的模型(因为总是 ready ),为了代码上的统一,做成线程池支撑,上层逻辑用协程描述也无可厚非(虽然现在新的 io 模型已经支持提交大量磁盘请求然后等一起完成了)
至于性能方面的提升,那有也只是副作用,即降低了编码复杂度导致可以从更高抽象角度优化业务逻辑,而不是拘泥于底层状态机的实现细节。
这里和同步 /异步,阻塞 /非阻塞其实关系不大,即使是一个纯算法,也可以使用协程来描述,generator 的模式和协程其实就差不多同构(可以互相转换),与其在需要数据时耦合上获取数据的代码,不如做一个 generator 将数据获取的过程抽象出来,generator 可以让你使用传统控制流结构来描述逻辑,同时内部状态就直接用 generator 中的局部变量表示。
PDX
2021-12-13 17:15:51 +08:00
协程解决了异步代码不能像写同步代码一样简单的问题。

都说什么调度啊,阻塞啊什么的,我觉得这都不是关键。关键是考虑一个程序员写代码的体验。在兼顾性能的情况下,安全且代码可读性强。
lbp0200
2021-12-13 17:17:23 +08:00
先创建一台 Linux 虚拟机,单核 1G 内存
yaphets666
2021-12-13 17:20:37 +08:00
看下来这玩意和 js 的 async await 很像啊
fpure
2021-12-13 17:25:52 +08:00
@yaphets666 async/await 就是协程啊
ming159
2021-12-13 17:28:29 +08:00
重要的事情 吼三遍
协程的目的不是提升性能! (当然比纯线程还是有提升的)
协程的目的不是提升性能!
协程的目的不是提升性能!

协程是简化了多线程开发难度!
协程是简化了多线程开发难度!
协程是简化了多线程开发难度!


可以用 多线程版完成一个 3 个生产者,2 个消费者程序,再用 Go 的协程+channel 实现一版,就更能体会到了, 更像是一种语法糖. 其意义在于从语法层面降低: 多线程 /异步 开发门槛.
kingofzihua
2021-12-13 17:37:21 +08:00
@ming159 谢谢,懂了
yulon
2021-12-13 17:40:08 +08:00
协程在最初是轻量级线程,而发展到如今在并发编程中其实是和闭包相对应的概念,只是一个是同步语义一个是异步语义。
有栈协程:轻量级线程,Windows 自带的 Fiber ,POSIX 在没有硬件支持下提供的 Pthread 。
共享栈协程:更轻量的轻量级线程,对栈内存需要小心操作,多用于没有原生支持无栈协程的语言。
无栈协程:异步闭包的语法糖,编译后的底层代码就是异步闭包。
KevinBlandy
2021-12-13 17:41:46 +08:00
好像 java 的 vertx 事件驱动模型,完全非阻塞。性能方面可以把 Go 的协程吊起来打。
fgwmlhdkkkw
2021-12-13 17:43:31 +08:00
避免空转
pkoukk
2021-12-13 18:12:11 +08:00
协程和线程的关系就像水果刀和杀猪刀
你说协程能解决什么线程解决不了的问题么?没有
协程纯粹就是更轻更方便
trcnkq
2021-12-13 18:27:48 +08:00
这玩意老有人的问关键就在于不懂得人也喜欢煞有介事地胡说八道说上两句,这导致每来个新人都需要经过大量的亲身体验才能去伪存真。
除了“协程”,还有__,__和__,你都能有这种体验。
notommorrow
2021-12-13 18:50:20 +08:00
协程是线程的实现之一
操作系统本身支持了线程和线程的调度,各种语言在实现自己的线程时通常会三类:
A. 程序线程 : 操作系统线程 1:1 , 即程序中的一个线程就对应操作系统的一个线程。这样程序就可以把线程的调度完全交给操作系统。但是 1.操作系统的线程数是有限的,因此 Java 可创建的线程数也是有限的,向 tomcat 常见的线程数量是几十个。2. 操作系统调度时,要从用户态切换成内核态,代价高(代价高是相对另外两种方式来说)
Java 之前的主流线程框架就是这么做的。一个典型的列子是,给 Java Thread 设定 Priority 不一定能生效。因为对 Thread 的 Priority 的处理是操作系统在处理。比如 Java 有 10 个 Priority 可能操作系统只有 5 个 Priority 。

B. (协程)程序线程和 :操作系统线程 N:1 , 即程序线程的调度完全由 程序自己处理,不依赖操作系统的线程调度。这样的好处:1. 线程数量不受限制 2. 线程调度不用切换用户态到系统态 。 坏处: 线程调度实现很麻烦。线程状态保存和恢复很复杂,一种常见的折中方案是,协程只支持无状态的函数式调用。

C: 程序线程 :操作系统线程 N:M, A ,B 折中


为什么需要协程: 协程在 java 里很早就被实现过 作为 Greed Thread 的概念。但是使用的不多,很快被废弃了。这些年微服务兴起,一个 web call 通常要数个 micro service 合作才能完成,http 请求数量指数级上升。微服务的特点, http 请求多,单个请求的处理时间短。这时候如果依靠 1:1 的线程实现,由于线程数量有限,当 http 请求数量超过一定数量级时,一个 http 请求在等待和调度上花费的时间甚至会超过任务执行所需的时间。 这时候很多人就希望一种线程方案,他能支持更多的线程个数,调度时间代价更少 -》 协程
kekxv
2021-12-13 19:00:44 +08:00
有个不太合适的举例:读取文件需要 300ms ,可以切换为 10 份或者 50 份,在中间穿插操作其它业务,可能最后的结果读取文件变成了 310ms 或者 400ms ,但是在这个过程中同时还处理了 n 个任务,虽然增加了读写文件的时间,但是少了线程的开销以及性能的占用,而这个 io 的时长是可接受的
lemonf233
2021-12-13 19:21:52 +08:00
@trcnkq #75
我猜其中一个空格是 IO 多路复用
aidoudou
2021-12-13 19:24:36 +08:00
进程:操作系统调度
协程:自己调度
Buges
2021-12-13 19:38:54 +08:00
cooperative multitasking 和 asyncio 和 concurrency 和 parallelism 是不同的事情,楼上不少人都搞混了。
单单回答楼主关于协程比线程轻量在哪里:线程( OS thread )是一种 preemptive multitasking 的实现,线程的切换由外部控制,对代码本身透明,不同线程之间相互争抢,当 cpu 切换时需要保存的状态很多(因为操作系统不知道你具体需要哪些,只能都保存下来)。而协程则是 cooperative 的,即你的代码在不需要时(如等待 IO )主动释放控制权,不同协程之间相互协作,切换时主动指明 resume 时需要的状态( async/await transform 成的 state machine 指的就是这些状态),所以更轻量,相应的代码也需要额外的复杂度,并且需要注意 blocking 问题(没有主动释放控制权)。
宣称 OS thread 开销大是因为内核态用户态切换之类的并不准确,因为操作系统也是可以实现 cooperative multitasking 的,只不过这样的系统上运行的用户程序如果出问题(没有主动释放)会卡住整个系统,所以通用操作系统都是采用的 preemptive multitasking 。

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

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

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

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

© 2021 V2EX