满足 stackful,能够自动 yield 的,有没有? 看了好几个都需要手动 yield 归还 cpu,感觉有点麻烦,希望大佬指点下,不奢求同时有 channel 和 select 了
1
keygen88 2020-10-28 11:59:07 +08:00 1
协程库很多,但很多其它库不支持就比较鸡肋了,这就是个生态问题。
|
2
reus 2020-10-28 12:21:41 +08:00 4
goroutine 本来就不是协程,对标的就是线程
|
3
ysc3839 2020-10-28 12:23:03 +08:00 via Android
自动 yield 大概要能插入代码吧? C++ 大概没有这种能力。
而且 C++20 的 stackless coroutine 出来之后,stackful 的可能会越来越少了。 |
4
abbycin 2020-10-28 12:26:21 +08:00 via Android
libgo 看过没?
|
9
nightwitch 2020-10-28 13:09:28 +08:00
|
10
zunceng 2020-10-28 13:18:31 +08:00
早几年用 asio coro 玩过
不过那个上面的 yield 就是对 for loop ... switch case 做了个封装 用起来还是太费脑 |
11
Yc1992 OP @nightwitch 补充一下,必须 c++11 哈
|
12
nannanziyu 2020-10-28 13:34:26 +08:00 via Android
@Yc1992
限定 c++11 的话,微软的 cpprestsdk 里有一个 pplx |
13
catror 2020-10-28 13:38:30 +08:00 via Android
用 asio+fiber 写过一个网络程序框架,用着也还行吧
|
14
CRVV 2020-10-28 13:55:40 +08:00 via Android 2
@Yc1992
如果你去看 Go 的官方文档,里面明确说了这东西不是 coroutine,当然它也不是 thread,所以才起了个新名字叫 goroutine 大家常说它是协程,是因为它和协程很像,在 io 上也用 epoll, kqueue, iocp 这些系统调用,并且它也确实在 io 操作上 yield 了,老版本上的调度器还不是抢占式的。 但首先新的调试器已经是抢占式的了,这就不符合协程的定义。然后你对比一下实现的细节,显然现在的 goroutine 和 thread 更接近。 别人怎么说并不重要,你得去看实际的东西。 |
15
Yc1992 OP @CRVV 不同的调度方式而已,https://golang.org/doc/faq#goroutines 里面明确提到了 coroutine
|
16
reus 2020-10-28 16:20:28 +08:00 2
@Yc1992 协程当然是协作式调度,但 goroutine 并不限制调度方式,现在的实现就是有抢占式的调度方式,跑着死循环的 goroutine 也可以被抢占,所以 goroutine 并不是协程。
FAQ 那段话是 11 年前写的: https://github.com/golang/go/commit/d4a4468204448843d0dd15d2d4b89c29607a4a7e 那时候的 goroutine 确实是协作式调度,没有任何抢占机制。但现在 goroutine 已经不是 11 年前那样了,FAQ 那段话是过时的了。不会有任何协程实现可以有 goroutine 这样的性质,就算可以自动调度,也做不到抢占式调度。只有线程具有抢占式调度的特性,所以说 goroutine 对标线程。 |
17
zzzbkl 2020-10-28 17:09:52 +08:00 via Android
试试 boost fiber
|
19
hdbzsgm 2020-10-28 17:51:12 +08:00
folly
|
20
wnpllrzodiac 2020-10-28 17:56:05 +08:00 via Android
st?
|
22
caviar 2020-10-28 18:50:35 +08:00
@sujin190 go1.14 的时候开始的 https://golang.org/doc/go1.14#runtime
|
24
BadMan 2020-10-28 19:17:46 +08:00
我在使用微信的 libco,挺好用的
|
25
hronro 2020-10-28 19:47:13 +08:00
居然这么多人说 Go 的 goroutine 不是协程,还有说可以抢占的就不是协程。
难道不是 stackful coroutine 都可以做到抢占吗? stackless coroutine 确实做不了抢占。 |
26
framlog 2020-10-28 19:58:06 +08:00
seastar
|
27
beidounanxizi 2020-10-28 20:18:40 +08:00
@reus 调度方式最新版本确实变了 尤其是 1.10 之后 ,但是 GMP 这一整套逻辑 是不是还是说和其他 coroutine 的差不多呢? 疑问脸.jpg
|
29
reus 2020-10-28 20:45:34 +08:00
@beidounanxizi 和哪个协程实现差不多?请举出例子,不要相当然。
|
30
hankai17 2020-10-29 00:00:41 +08:00 via iPhone
swapcontext
|
31
reus 2020-10-29 01:03:44 +08:00 1
另外就普适性而言,和 goroutine 对等的,也是线程。在 go 里,你只能用 goroutine,不存在其他并发单元。而 C/C++
里,能担当这个任务的,只能是 pthread 这类线程库,而不是其他协程库,因为协程库还没有统一的标准,你用这个,他用那个,没法融合的。 另外,虽然现在主流 pthread 实现,都是 1:1 映射到系统线程,但是,M:N 映射到系统线程的 pthread 实现,也是存在的。pthread 线程,和 goroutine,都只是并发的单元,具体怎么实现,对于使用者是不可见的。goroutine 历史上曾经实现为纯协作式调度,不代表它就是协程。因为它加入抢占式调度之后,程序也不需要变化,怎么调度都不影响语义,这是协程不具备的性质。协程语义一般都会有确定的调度点,例如 yield 语句、await 语句,而不会是任何地方。 |
32
Balthild 2020-10-29 04:04:12 +08:00
@reus 从普遍意义上讲,「抢占即非协程」似乎不那么绝对。比如,Rust 有抢占式的异步运行时实现,比如 tokio 、smol 等。若按「抢占即非协程」定律,Rust 的异步就不是协程了。但 Rust 异步的设计明确自己是 stackless coroutine 。这需要如何解释呢?
|
33
missdeer 2020-10-29 08:52:55 +08:00
赞同 31 楼。
早些年,coroutine 概念还几乎不见于日常开发,很多操作系统(比如 DOS,一些 UNIX )还不支持内核线程时,有第三方库(比如 pthread)实现用户态线程及调度,当然后来 pthread 的实现也千变万化。 |
35
reus 2020-10-29 09:21:55 +08:00 2
|
36
reus 2020-10-29 09:28:02 +08:00 1
@Balthild 划出 tokio 文档里的重点给你:
A common solution to this problem is preemption. With normal OS threads, the kernel will interrupt execution every so often in order to ensure fair scheduling of all threads. os 线程支持抢占 Runtimes that have full control over execution (Go, Erlang, etc.) will also use preemption to ensure fair scheduling of tasks. go 、erlang 也支持抢占 This is accomplished by injecting yield points — code which checks if the task has been executing for long enough and yields back to the scheduler if so — at compile-time. 插入调度点,这是 go 过去的做法,现在增加了用信号去抢占的方式 Unfortunately, Tokio is not able to use this technique as Rust's async generators do not provide any mechanism for executors (like Tokio) to inject such yield points. tokio 不支持抢占 你的大前提错了,推论自然全错。 |
37
CRVV 2020-10-29 10:20:28 +08:00 1
@Balthild
@hronro https://en.wikipedia.org/wiki/Coroutine#Comparison_with_threads 协程,coroutine,co 是 cooperatively,合作协作的意思。 相对的概念是 preemptively,抢占 这是这个 coroutine 原本的意思。 在一个 stackful coroutine 的实现上加上抢占式调度,那当然可以做。 但做出来的东西就不叫 coroutine 了。 |
38
CRVV 2020-10-29 10:53:49 +08:00
@Yc1992
我本来想说的就是这一段。 When a coroutine blocks, such as by calling a blocking system call, the run-time automatically moves other coroutines on the same operating system thread to a different, runnable thread so they won't be blocked. 这里说的不是把多个 coroutine 放到同一个线程上来跑。是说如果有一个 coroutine 阻塞住了一个 thread,就把其它的 coroutine 放到别的线程上跑。 然后有一句话,The programmer sees none of this, which is the point. The result, which we call goroutines, ... 所以总结一下就是,有一个协程,它 block 住了(比如在 python 的 async function 里面写了一句 time.sleep ),这样其它的协程就不能跑了对吧,那我们写一个高级一点的 runtime,把能跑的协程放到其它 thread 上跑。 并且把这些过程都隐藏起来,什么 yield 之类的东西都没有了,都是 runtime 里面的事情。 所以说这是一个基于 coroutine 的想法,或者说是一个经过了大改的 coroutine,还专门说了这个东西叫 goroutine 不叫 coroutine 了。 所以还是上一条回复里面说的,它改完了就不是 coroutine 了。 |
40
user8341 2020-10-29 11:29:04 +08:00
各位大佬,golang 什么情况下会调用 调度器?
我知道的有以下这 3 个: 1. syscall 2. go 语句 3. 阻塞读写 chan 普通函数调用会不会调用 调度器? |
41
user8341 2020-10-29 11:31:40 +08:00
另外,1.14 版加入了时间片,时间片用完 sysmon 会通过发送 signal 给线程的方式,强制一个 goroutine 调用 调度器。
|
42
dollar 2020-10-29 13:17:05 +08:00 via iPhone
brpc 中的 bthread 挺好用的
|
43
joydee 2020-10-29 13:48:18 +08:00
可以尝试看看 Rangev3 作者 Eric Niebler 用过的 c++ coroutine 库,链接[https://github.com/lewissbaker/cppcoro],遵从 C++ coroutines TS N4680,不过代码还是蛮晦涩的,慎用
|
44
Balthild 2020-10-31 14:32:50 +08:00
@reus 原来如此。也就是说,只有可以真正地打断比如死循环这种阻塞操作的才算是抢占式的,所以抢占的肯定不是协程,这点上没问题了。
但 async-std 的确也有一个 PR (之前记成了 tokio,看了你贴的文章才想起来)能做到自动检测阻塞,然后把其他协程放在新线程。这样的做法虽然不是抢占式,但也能达到没有确定的调度点、任何地方都可能调度的效果。那么这种运行时要怎么看待呢,是不是严格来讲也不属于协程了? |