wmwm
V2EX  ›  程序员

为什么只有 go 语言原生支持协程?

By wmwm at 2023 年 8 月 10 日 · 8619 次点击

大部分语言的协程都是基于 epoll/select 机制,由于 epoll/select 只能处理 IO 问题,所以导致大部分语言的协程也只能处理 IO 问题

而 go 语言的协程可以在任何情况下使用,是真正意义上的协程,底层是通过汇编指令 pop/push 保存上下文

以上理解正确吗?

46 条回复  •  2023-08-12 18:37:30 +08:00
nightwitch
   1
nightwitch  
   2023 年 8 月 10 日 via Android   ❤️ 2
把协程的实现放到库来做还是放到语言特性里只是语言设计者的偏好问题。协程和 epoll 也是正交的关系,没什么基于不基于的。
thinkershare
   2
thinkershare  
   2023 年 8 月 10 日
因为协程并不是什么先进值得被其它语言吸收的好东西,纯粹是语言创建者的个人偏好。
coderxy
   3
coderxy  
   2023 年 8 月 10 日   ❤️ 1
因为现在流行的几个语言里面,就属 go 诞生的最晚,其它语言有一定的历史包袱。
DonaidTrump
   4
DonaidTrump  
   2023 年 8 月 10 日
Java 也原生支持了
emSaVya
   5
emSaVya  
   2023 年 8 月 10 日   ❤️ 8
你可能需要重新理解协程的概念。

另外应该是 2015 年前后 大批程序设计语言都上了 coroutine, 比如 c# js python 。什么概念时髦了就上什么。

c++ coroutine 讨论了得有几十年了, 现在 c20 也加上了。
duke807
   6
duke807  
   2023 年 8 月 10 日 via Android
各语言协程的底层都是通过汇编指令 pop/push 保存上下文
lovelylain
   7
lovelylain  
   2023 年 8 月 10 日 via Android
@duke807 async/await 这种是状态机
agagega
   8
agagega  
   2023 年 8 月 10 日 via iPhone   ❤️ 1
协程和用户态线程是不同的东西,只是 go 利用特殊设计在后者实现了前者的要达到的效果。Swift 的并发支持也有点异曲同工之妙
sunny1688
   9
sunny1688  
   2023 年 8 月 10 日   ❤️ 2
yield 就是协程,很多语言都支持协程的,只不过没有语言层面实现调度器(运行时)
touchmii
   10
touchmii  
   2023 年 8 月 10 日
就一个 runtime 的事情, 想支持啥特性都可以, 至于 go 为什么要放到语言特性中来自然是要宣传造势, 这是它最显著的特点.
kenvix
   11
kenvix  
   2023 年 8 月 10 日
先问是不是,再问为什么。
R4rvZ6agNVWr56V0
   12
R4rvZ6agNVWr56V0  
   2023 年 8 月 10 日
x y problem
oldshensheep
   13
oldshensheep  
   2023 年 8 月 10 日
golang 的协程有两种抢占式和协作式,抢占式类似于 Java 的虚拟线程,协作式类似于 yield
支持类似于 Golang 的抢占式的协程的语言有 Java ,其他的语言好像不怎么支持
nuk
   14
nuk  
   2023 年 8 月 10 日   ❤️ 4
golang 从来都没有协程,goroutine 本质上是 M:N 的用户线程。
官方的说法:
A goroutine is a lightweight thread managed by the Go runtime.
WebKit
   15
WebKit  
   2023 年 8 月 10 日 via Android
Kotlin 也支持
ravenl
   16
ravenl  
   2023 年 8 月 10 日
go 的协程还没出啊
https://research.swtch.com/coro
AItsuki
   17
AItsuki  
   2023 年 8 月 10 日   ❤️ 4
goroutine 确实不是协程。协程最关键的一点是非抢占式调度,可以显式的挂起和恢复,而不是阻塞。
ikas
   18
ikas  
   2023 年 8 月 10 日
不正确
WaldenHorizon
   19
WaldenHorizon  
   2023 年 8 月 11 日
不懂,但 goroutine+channel 做 IO 并发真的超爽
lightjiao
   20
lightjiao  
   2023 年 8 月 11 日 via iPhone   ❤️ 1
yulon
   21
yulon  
   2023 年 8 月 11 日
你完全说反了,Go 的底层就是 Epoll/IOCP/Kqueue ,你就算不使用网络功能,它默认就是用的 net poll ,因为它就是发明来解决网络问题的语言😅
holulu
   22
holulu  
   2023 年 8 月 11 日
Go 诞生的目的是为了提升编写多核及网络应用的效率,其特性的设计肯定就围绕这个目标的。
hankai17
   23
hankai17  
   2023 年 8 月 11 日
我认为 任何语言都可以实现自己的协程
但是很少有像 go 那样 自带协程调度器
还有我认为 抢占/非抢占 区别就是主动/非主动的'yeild'当前上下文 对于协程实现来说 不是特别难
所以我认为 原生支持协程 原生就意味着 有协程调度器
lysS
   24
lysS  
   2023 年 8 月 11 日
go 的调度就是依赖系统的异步模型啊,这样可以在 go 里面用同步代码写异步逻辑,而不用一堆回调;像文件 io 没有异步模型,go runtime 只有锁定 M
GeminiPro
   25
GeminiPro  
   2023 年 8 月 11 日   ❤️ 1
只有 go 自带调度器了
weishao2011
   26
weishao2011  
   2023 年 8 月 11 日
1 、epoll/select:确实,很多基于协程的异步 I/O 库利用了 epoll (在 Linux 上)或 select 来进行非阻塞 I/O 操作,以支持高并发。这些机制主要处理 I/O 问题,如网络通信、文件读写等。

2 、大部分语言的协程只能处理 IO 问题:这不完全正确。协程的本质是一种轻量级的线程抽象,用于支持高效地切换执行上下文。而是否主要用于 I/O 取决于其使用场景和设计目的。有些系统和库的确重点强调了 I/O ,但协程本身的设计和实现并不局限于此。
githmb
   27
githmb  
   2023 年 8 月 11 日
那 Rust 就不算原生支持了吗
Huelse
   28
Huelse  
   2023 年 8 月 11 日
实际上都是跑在系统线程上的,只是调度方式不同罢了。
cosmain
   29
cosmain  
   2023 年 8 月 11 日   ❤️ 1
cosmain
   30
cosmain  
   2023 年 8 月 11 日
IO 多路复用需要系统底层提供支持来实现一个线程中监控多个文件描述符的 IO 事件,但是通常你去真正读写的时候,还是会打开新的线程。

协程是一个语言层面的抽象,只需要语言提供库和特性,和系统底层无关,通常是用户态的“技巧”,旨在在一个线程中处理多个“task”,达到减少内核线程存储、上下文切换等开销。
mmdsun
   31
mmdsun  
   2023 年 8 月 11 日
正意义上的协程??到现在协程本身没有一个统一的定义吧,而是一个广泛的概念。
https://en.wikipedia.org/wiki/Coroutine

其实用汇编也能做到的,不一定需要基于 epoll/select 机制。
而且这个也不是异步 IO 。IOCP 、Linux 5.1 以后的 io_uring 了解下。

协程和 IO 多路复用关联不是很强。通常说协程是一种编写并发代码的方式,可以在某些点暂停和恢复它们的执行不阻塞主线程。

你用 goto 、lablel 跳转+状体机写,也能算 coroutine 吧?( stackless coroutine )
FlashEcho
   32
FlashEcho  
   2023 年 8 月 11 日
C++20 也有协程了,也是任何条件下可以用的函数
wanguorui123
   33
wanguorui123  
   2023 年 8 月 11 日
协程、虚拟线程、事件队列,实现目的都类似
wonderblank
   34
wonderblank  
   2023 年 8 月 11 日
> 大部分语言的协程都是基于 epoll/select 机制,由于 epoll/select 只能处理 IO 问题,所以导致大部分语言的协程也只能处理 IO 问题

不正确,协程和 epoll 不是一个东西,也不是说基于什么。你可以理解为协程是香蕉,epoll 是体重。epoll / select / kqueue 是多路复用的实现方案而已。可以配合协程使用。


> 而 go 语言的协程可以在任何情况下使用,是真正意义上的协程,底层是通过汇编指令 pop/push 保存上下文

不正确,首先没办法定义`真正意义上的协程`是什么,以及底层基本上都一样。

> 以上理解正确吗?

全部不正确

基本上可以用任何语言实现协程。

@wanguorui123

> 协程、虚拟线程、事件队列,实现目的都类似

不正确。设计他们,以及背后的原因都各不相同。对于特定的问题没有银弹,所以出现了很多方案。
w950888
   35
w950888  
   2023 年 8 月 11 日
@WebKit kotlin 标准库不支持协程
oxromantic
   36
oxromantic  
   2023 年 8 月 11 日
lua 是在 bytecode 层面的协程,用的 longjmp ,完全不用线程等机制
zjsxwc
   37
zjsxwc  
   2023 年 8 月 11 日
完整的协程,php8.1 也有
https://www.v2ex.com/t/953310#reply0
vizee
   38
vizee  
   2023 年 8 月 11 日
先问是不是,再问为什么
wanguorui123
   39
wanguorui123  
   2023 年 8 月 11 日
@wonderblank 设计目的都是为了高吞吐量,榨干系统性能
luoqeng
   40
luoqeng  
   2023 年 8 月 11 日
问题的关键应该是协程调度器实现
其他语言库一般用来处理网络 io ,只是利用 epoll/select 来实现调度器,Go 没有依赖 io 复用来实现调度器
wetalk
   41
wetalk  
   2023 年 8 月 11 日
回到线程的定义:操作系统能够进行运算调度的最小单位。协程不是必须的
wonderblank
   42
wonderblank  
   2023 年 8 月 11 日
@wanguorui123

> 设计目的都是为了高吞吐量,榨干系统性能

你年纪太小了,也不能说你错。
charlie21
   43
charlie21  
   2023 年 8 月 11 日
Golang 采用的 CSP 模型和 Erlang 的 Actor 模型
https://zhuanlan.zhihu.com/p/27341488
julyclyde
   44
julyclyde  
   2023 年 8 月 11 日
能提出这种问题,说明思维方式有问题
bthulu
   45
bthulu  
   2023 年 8 月 12 日
epoll 又不是什么牛逼机制, 纯属微软作死导致 epoll 在服务端一家独大. 你可以试试 iocp, 比 epoll 强多了, 偏偏支持的没几个.
inshua
   46
inshua  
   2023 年 8 月 12 日
erlang 早就有了,那几年 erlang 火了一阵,后来实在太非主流了用的就少了,但是设计思想传播出去了就有了一堆衍生,当然协程出现的更早,但是在并发领域用协程 erlang 应该算是早的
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
© 2026 V2EX · 163ms · 3.9.8.5