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

2023-08-10 13:27:31 +08:00
 wmwm

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

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

以上理解正确吗?

6905 次点击
所在节点    程序员
46 条回复
yulon
2023-08-11 07:16:07 +08:00
你完全说反了,Go 的底层就是 Epoll/IOCP/Kqueue ,你就算不使用网络功能,它默认就是用的 net poll ,因为它就是发明来解决网络问题的语言😅
holulu
2023-08-11 08:28:39 +08:00
Go 诞生的目的是为了提升编写多核及网络应用的效率,其特性的设计肯定就围绕这个目标的。
hankai17
2023-08-11 08:32:51 +08:00
我认为 任何语言都可以实现自己的协程
但是很少有像 go 那样 自带协程调度器
还有我认为 抢占/非抢占 区别就是主动/非主动的'yeild'当前上下文 对于协程实现来说 不是特别难
所以我认为 原生支持协程 原生就意味着 有协程调度器
lysS
2023-08-11 09:15:22 +08:00
go 的调度就是依赖系统的异步模型啊,这样可以在 go 里面用同步代码写异步逻辑,而不用一堆回调;像文件 io 没有异步模型,go runtime 只有锁定 M
tyrantZhao
2023-08-11 09:43:10 +08:00
只有 go 自带调度器了
weishao2011
2023-08-11 10:07:36 +08:00
1 、epoll/select:确实,很多基于协程的异步 I/O 库利用了 epoll (在 Linux 上)或 select 来进行非阻塞 I/O 操作,以支持高并发。这些机制主要处理 I/O 问题,如网络通信、文件读写等。

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

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

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

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

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

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


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

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

> 以上理解正确吗?

全部不正确

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

@wanguorui123

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

不正确。设计他们,以及背后的原因都各不相同。对于特定的问题没有银弹,所以出现了很多方案。
w950888
2023-08-11 14:42:18 +08:00
@WebKit kotlin 标准库不支持协程
oxromantic
2023-08-11 14:45:36 +08:00
lua 是在 bytecode 层面的协程,用的 longjmp ,完全不用线程等机制
zjsxwc
2023-08-11 14:59:20 +08:00
完整的协程,php8.1 也有
https://www.v2ex.com/t/953310#reply0
vizee
2023-08-11 15:01:12 +08:00
先问是不是,再问为什么
wanguorui123
2023-08-11 16:00:03 +08:00
@wonderblank 设计目的都是为了高吞吐量,榨干系统性能
luoqeng
2023-08-11 16:29:20 +08:00
问题的关键应该是协程调度器实现
其他语言库一般用来处理网络 io ,只是利用 epoll/select 来实现调度器,Go 没有依赖 io 复用来实现调度器

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

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

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

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

© 2021 V2EX