![]() |
1
huluhulu 3 天前
C++有协程啊,谁说没有的。。。
|
2
Donahue 3 天前 ![]() 线程有上下文切换开销,协程没有(或者更小?)
线程占用内存大,协程占用内存更小,可以使用更多协程 协程更多是为了异步/减少阻塞吧(不知道对不对哈) 为了减少阻塞,从 callback function -> async/await -> 协程 当遇到阻塞的时候,协程可以由协程调度器调度到其他协程,并且上下文切换的开销小。 如果换作线程,阻塞就浪费 cpu 了。 c++有协程了 |
4
w568w 3 天前 ![]() > 在我看来 go 的协程实现是分割原本线程的资源,做到更轻量化和更灵活的资源调度
没什么问题。更具体地说,很重要的一个原因是 userspace thread 完全省略了操作系统调度线程和内核态切换的开销。 有一个类似的例子:为什么 C 语言里用 malloc() 分配内存,而不是直接调操作系统提供的 sbrk()?你让面试官想去吧。 > 他还有第二个问题,既然协程这套理论这么牛逼,那么 c++ 为什么没有呢 没更新过知识的愚昧认知。当今几乎所有现代语言里都有「协程」,只是具体含义和实现不同。我随便抓一把:Python 、JS/TS 、C++、Rust 、C#、Java/Kotlin 、Lua 、Dart… |
![]() |
5
so1n 3 天前
假设你有一件事的情况下,协程的管理消耗时间远远大于执行时间,线程能比协程更快。但是你有很多件事的情况下,协程能省下很多上下文切换的开销,这部分远远大于协程的管理时间
|
6
sardina 3 天前
goroutinue 的上下文切换是比线程要轻量的,还有一个 goroutinue 初始化只需要才 2K 的内存,一个线程就要 8M ,随便并发一下都比线程的并发多很多
|
7
strobber16 3 天前
这人技术和处事都有问题,要是入职后是你直接上级或者同组的话,这个岗可以直接 PASS
|
8
kneo 3 天前 via Android ![]() 一个协程不会比一个线程更快,但是一万个协程很可能会比一万个线程更快。因为线程本身就是一种资源。你们讨论的“消耗资源”太含糊了。争执前先定义清楚。
|
9
w568w 3 天前 ![]() @w568w 还有个老生常谈的称呼问题:
协程 = 有栈协程/虚拟线程/用户态线程。这是在说 Go 的 goroutinue 、Java 的 Virtual Thread ; 协程 = 无栈协程/暂停之后能恢复的函数。这是在说 Python/Dart 的 Iterator 、Lua/C++20 的 Coroutines 、Rust 的 Future 状态机; 协程 = 可以指包装了一层 Dispatcher 的普通线程。这是在说 Kotlin 的 Coroutine + NewThreadDispatcher 。 |
10
ly841000 3 天前
协程不是为了提高任何效率, 而是为了将异步编程简化成同步化, 1:N 有栈协程好几十年了, unix 和 windows 都有专门的 api, 不是什么新概念, 无栈协程是最近些年编译器进步兴起的
|
![]() |
11
qxdo1234 OP @strobber16 别人直接就把我 pass 了,他是一面,他觉得我回答的技术不太行。
|
![]() |
12
lance6716 3 天前 via Android
> 那么何谈加快运行效率,你原本线程要做的事还是没变,而且还多了管理协程的开销
> go 的协程比系统的线程更慢 老哥你是真分不清这两种表述吗… 一个 CPU 密集的任务,机器不切换协程要跑 100 秒,管理协程花 1 秒,因此 101 > 100 协程更慢 |
13
NotLongNil 3 天前
要搞清楚一个事,每一个问题,都是有其前提条件的。比如,面试官说线程比协程快,如果前提条件是并发数很低的情况(并发数比 CPU 核心数少),那么是对的。你认同的观点,同样也是有前提条件的。讨论一个问题前,要先划好场景,不然就是没完没了,毫无意义的扯皮。这家公司 pass 吧
|
14
cnbatch 3 天前
|
![]() |
15
sagaxu 3 天前 ![]() 协程运行在线程内,怎么可能比线程更快?越是 CPU 密集型场景,协程越无用。线程跟 CPU 核心 1:1 绑定,设定好亲和性,才是最快的,多 CPU 时还要考虑 NUMA 尽量访问本地内存。
协程搞到冒烟,也不可能比手搓的多线程实现更快,只不过多线程实现复杂度较高。 |
16
dearmymy 3 天前
协程就是,一个线程里调度运行的函数。简单讲,当去做 io 读取操作,其实很多时候是内核在读取,用户态这时候没必要等着内核读取完,把这段时间给其他函数运行,等内核读取完后继续运行。
最常见场景,爬虫,每个请求中间大量是等待 io 读取网络时间,这时候用协程就好。 还有一个 ui 常见例子,点击读取 button ,去读一个大文件并显示当 list 里,以前为了不卡死 ui 要不异步去读,要开线程,都会回调满天飞。协程就好,ui 线程读取大文件,等待过程还继续处理 ui 事件,然后读取完,继续显示列表,甚至代码逻辑就在一起。 线程是要有一套自己资源,开一个线程是废资源,其实现在配置无所谓,只不过多线程代码很多问题。但是如果代码都非 io 操作那就只能多开线程,这时候协程就没用了。 |
![]() |
17
bronyakaka 3 天前 ![]() 1 、goroutine 初始栈 2KB (会动态增长的,并不是说一定省内存了),而操作系统线程的栈通常 1MB
2 、Go 运行时内置调度器,相比线程由操作系统调度,goroutines 的上下文切换成本更低,避免内核态的开销。 3 、配合通道减少了竞争的问题,使用简单 缺点也有: 1 、没法控制怎么分配到 cpu 核上,开几个协程可能都挂一个线程上,,利用不了多核资源 2 、GUI 生态多是线程绑定,go 对这块的兼容很不好,没什么生态 3 、协程一旦执行阻塞系统调用,会把整个线程阻塞,导致该线程无法执行其他 goroutines ,降低并发效率 4 、协程不适合 CPU 密集型任务,因为没什么 io ,上下文切换反而增加了开销,,调度器也有损耗,不如用多线程直接绑定到核心上 |
![]() |
18
CEBBCAT 3 天前 ![]() “耗费资源”这个概念在你们交谈里面变得很模糊,欠缺定义。
楼主经验少点,工作几年了哦?可以刷些 Go 实现、Linux 调度的文章,了解下进程这块相关的知识。 面试官应该到最后解释一下的。 Go 的协程就是用户(态)自己管理的代码片段嘛,那资源的分配上相比 OS 提供的线程,肯定是能够自己 DIY 啦 至于 CPP ,那 CPP 人家是写 OS 的语言,我拿 CPP 写个 Linux 再写个 Golang 编译器,你说我 CPP 有没有协程? https://draven.co/golang/docs/part3-runtime/ch06-concurrency/golang-goroutine/ https://samwho.dev/memory-allocation/ https://www.luozhiyun.com/archives/518 https://draven.co/golang/docs/part2-foundation/ch04-basic/golang-function-call/ |
19
MrKrabs 3 天前
你 CPU 跑满那肯定是系统线程快啊,但是你 CPU 跑满的东西你用 go 写?
|
20
mooyo 3 天前
计算密集型肯定是更慢的,协程主要是方便让一个程序更好的写成“正确的”并发模式。
|
21
fanxinxiaozhan 2 天前 via Android ![]() cpu 密集型用线程,io 密集型用协程
|
![]() |
22
fgwmlhdkkkw 2 天前 via Android
@MrKrabs 这种情况在 go 里面也是一样啊,全是计算的时候,go 也没办法打断吧。
|
23
hefish 2 天前
op 哥,你碰到了一个杠精面试。pass 吧。。。
|
24
000sitereg 2 天前 via Android
其实也没那么复杂。一般又通俗的理解就是计算机的东西越底层效率越高,协程基于线程就不可能比线程的效率高。
|
25
DIO 2 天前
我面试过一个号称某大厂主任级别的技术管理,结果我们聊关于国内外( b 站,油管等)视频下载技术问题。我不太懂但是市面上有这么多盗版视频,总不能都是内部泄漏的吧,就觉得肯定有办法。他让我回去好好看看,说现在大厂都有办法杜绝任何方式扒源。。。
|
26
testcgd 2 天前 via Android ![]() 你们不在一个频道上啊,你应该一顿 gmp 叭啦叭啦上去糊他一脸
没有啥是协程能做线程不能做的,用户态写个协程库就等态了 1 、协程是为了提高资源利用率和减少上下文切换的开销 2 、c++也有协程,只是不是语言层面上的 |
27
kingcanfish 2 天前
@qxdo1234 #3 https://github.com/Tencent/libco 微信的 cpp 协程库 还有 这面试官水平太臭
|
28
Flourite 2 天前
水货
1. goroutine 也是要线程来运行的啊,性能只会一样 2. linux 线程栈空间 8M ,相关上下文切换需要保存的寄存器等资源比 g 更多 3. 让他看新闻,c 跟 cpp 都有 coroutine |
29
xjzshttps 2 天前
线程成本高:
* 线程堆栈占用内存大 * 线程切换成本高,是需要内核才能切换 协程成本低: * go 的堆栈是动态的,最初只会使用很小的内存空间 * go 协程切换是用户态的,成本低 另外 go 适合 io 密集型的,原生线程适合计算密集型。 |
![]() |
31
agagega 2 天前 via iPhone
我总觉得这个面试官是喜欢在网上刷语言不重要,重要的是思想的那类人🤣
|
32
fds 2 天前
其实前面不少回答已经很准确了,我就补充下面试官的想法。面试官无非是想看看你对程序运行时的理解是否足够深入。Go 算是 C 语言的加强版,像 GC 、map 、channel 这些,你用 C 写就得找库或者自己实现,但 Go 就给你包装好了。协程也是一样,你用着是协程,但底层还是在线程上跑的,只不过 Go 帮你把调度逻辑写了,一个线程上可以根据需要不断切换执行各个协程的逻辑。你自己也可以实现这个,但太麻烦,而且大多数人写不对。至于为什么必须有线程,那是因为操作系统就只支持到线程。所以面试官说的确实没问题,算是考察下操作系统吧。当然这个知识点我觉得也就是层窗户纸。
|
33
mayli 2 天前
> 不耗费资源的操作时,协程要更快,在耗费资源较多时,还是线程更快。
有点笼统,资源的定义是啥没说清楚,不过 > 总的来说是可以加快程序的运行效率 这一点肯定不对,协程仅仅是增加了程序的并发度,效率不一定高。一般来说,协程和线程都是解决 IO 阻塞时 cpu 空闲问题,协程可以实现更高阻塞并发,线程虽然并发程度没有协程高,但是总体上一般认为效率比协程还是高的。这里的效率指的是,协程还需要额外的开销进行 cooperative 部分,比如把异步、回调包成类似同步的操作。 换一个说法,就对于非阻塞 IO 密集型任务,比如 CPU 上纯纯的 for-loop ,协程就毫无用处。 你回答给人感觉认识不够清晰,估计就 pass 了。或者是你跟他不匹配,觉得沟通费劲,至少你自己也觉得跟他沟通费劲,以后做同事也没意思。不如友好 byebye |
![]() |
34
liangzaiyi 2 天前
搞好前提就方便回答了。如果是 CPU 密集型,直接线程数等于 CPU 核数行了;如果是 IO 密集型,就算是单线程跑协程也比多线程好,资源的分配都不是一个级别的,可以搞一百万个协程,你试下搞一百万个线程看炸不炸。
|
35
Cannly 2 天前 via iPhone
认同 15 楼说法。面试官的问题应该分场景的。
如果一个线程的任务就是能跑满一个时间片,而不会在自己的时间片中提前结束任务,那么协程完全不必要。但是如果一个线程所分配的任务,比如只需要 1/10 时间片,那么,引入协程改造,确实能把未引入协程时给其它 cpu 的任务,以协程调度方式继续在本线程运行。这就减少了线程切换,更大限度的利用了 cpu 。 但是别忘了,操作系统调度的是线程作业,程序尽早出让某个线程 CPU 也是一种协调。尽可能霸占未必主流大部分程序 |
![]() |
36
qxmqh 2 天前
太纠结技术细节,从对话能看出来,即使进入岗位,以后你的日子也不好过。
|
![]() |
37
cowcomic 2 天前
如果只讨论协程和线程自身内部运行时的性能,那一定是线程更好
但线程的代价更高,占用的系统资源更多,创建线程的时间更长,线程间的资源交互更慢 所以在使用层面是需要通过应用场景来确定具体用哪个 |
38
hwdq0012 2 天前
c++17 之前 Boost fiber(类似 go 的协程) , boost croutine(没有调度器的协程) 都是有栈协程, c++17 开始 msvc 先有无栈协程, cpp 20 开始 各编译器都陆续有无栈协程了
|
39
HaibaraDP 2 天前
计算π值,我认为线程还是比协程快的,毕竟协程在线程的基础上套了一层。对于面试问题,应该反复和面试官沟通,确认他的问题后给出答案
|
![]() |
40
LotusChuan 2 天前 ![]() 这不是技术问题,是面试套路问题。面试得看人下菜,这也是体现沟通能力的一环。
问题 1 他想听到的就是协程适合 IO 密集型的业务,线程适合 CPU 密集型/普通业务。因为搜索引擎去搜网上论坛都是这种回答,面试官看过所以拿来问了,你得和他看的八股保持一致。 问题 2 他想听到的是协程很复杂,相比于线程来说会增加代码复杂性。他这么问的原理同上,网上论坛都是这么说的。至于 C++到底有没有协程他无所谓。 如果你有信心和能力说服面试官,那么再去尝试说服,不然就借坡下驴背他想听的八股就行了。一般来说面试官是说服不了的,因为他控制你面试是否通过的权力,为什么要接受你那一套?毕竟他自己那套也不是全错。 搜索引擎搜 rust async vs thread 的结果,第一条是 Reddit ,第二条是 Stackoverflow ,完全匹配面试官思路。 https://www.reddit.com/r/rust/comments/jgpvi3/asyncawait_vs_threadsatomics_and_when_you_use_each/ https://stackoverflow.com/questions/78541829/async-thread-vs-std-thread |
41
zzhirong 2 天前
两者本质上都可以抽象成,一个线程池在完成多个任务队列,那么问题来了,既然两者都差不多,然后,Go 还引入了
goroutine 抽象层,为什么 Go (可能)要高效一些。如果所有任务都是非阻塞的,那么多线程和 goroutine 在性能表现上差别可能并不明显(猜想,未验证);但在现实情况中,由于 I/O 或通信等原因,不可避免会发生阻塞。传统线程一旦阻塞,则会占用整个线程资源,而 goroutine 在阻塞时会被挂起,并在等待条件满足后重新调度,大部分时候不会需要阻塞底层线程,从而更高效地利用系统资源。也就是说,如果你很 NB ,能够做到又能尽量少阻塞线程,又能把任务完成(也就是高效利用线程池,这就是 Go 调度器做的事情),那么两者差别不会很大。 |
42
leonhao 2 天前
根据实际业务测一下就知道了,嘴上说有啥用
|
43
hashakei 2 天前
|
![]() |
45
sagaxu 2 天前
@moudy 协程不过是多线程+运行队列调度+当前 task 的上下文保存/恢复,go 是从语言层面做的,kotlin 是从库层面做的,还有一堆人用 C/C++做了类似的事情,没有什么同步方式是协程能用,线程却用不了的。二十多年前,putty 作者写 putty 的时候就用寥寥数行代码实现了上下文的保存和切换。
|
![]() |
46
cexll 2 天前
刷一下 linux 底层进场线程协程的位置就知道 内核态和用户态 协程在用户态 创建与销毁都在内核态操作的
|
47
iOCZS 2 天前
首先切换效率,协程更高。
其次,为什么要切换? io 的时候,让出 CPU 资源给其他任务运行,提高运行效率。 线程爆炸的时候,线程会一直切换。协程一般会控制任务队列(线程数),让多个协程在有限个线程内切换。 如果每个核心都进行 CPU 密集运算,那效率会比进行额外协程切换的高。 |
49
leetom 2 天前
我觉得不一定是他要让你相信他的理论,而是对你的回答不满意,通过提出一些不一致的看法,让你深入回答问题,看看你的基本功。
|
50
laminux29 2 天前
简单来说,启动一次线程去干活,相当于从家里出发去公司干活。线程干完一件事情后,还要回家。接到新任务需要从家里再次出发。协程就没这么多事,一直呆在公司,干完一件事情后,不需要回家,继续在公司干别的。这不效率差别就体现出来了。
|
51
moudy 1 天前
@sagaxu thread 和 coroutine 最大的区别就是上下文切换是否自主可控。因为 thread 切换不可控,所以要应付数据一致性的地方比 coroutine 多得多。相关的开销也大不少。我之前帮同事用高级语言模拟一些不依赖底层的同步方案( bare metal ),在模拟时真的是能很明显的体会这两种技术方案在效率上和 deterministic 上的区别。
|
![]() |
52
sagaxu 1 天前
@moudy 怎么不可控了?是完全要自己控制,不受外部干预。多线程+task 队列,切换只不过是从队列的 A 元素切换到 B 元素,不是从 A 线程切换到 B 线程。跟 goroutine 的大区别只有一个,多线程+队列是非强占式的,task 不主动释放就会一直占用,goroutine 调度可以抢占。netty 和 vertx 就是多线程+队列,性能差吗?
|
53
liuguang 1 天前
go 语言协程的主要用途是哪里,是 web 开发。
web 后端最常见的任务就是等 io ,比起计算任务 io 操作是非常耗时间,而线程遇到 io 操作会卡住,完全不能做任何事,而协程这时候就可以挂起 io 去处理其它事情,所以看上去协程的效率更高。不过实际上协程本质上也是线程,甚至是多个线程合力都有可能,这句话不假,你可以把协程看成一种精心设计好的线程,但是它能在遇到 io 阻塞时,继续去做其它事情。 但是协程就一定比普通线程更快吗,其实并不是的,rust 的异步里面也说了异步操作不一定更快,所以 rust 语言不仅有异步语法,也有原生线程,从而可以看情况来选择。与此相比 go 语言只提供了协程来处理并发,在需要原生线程的地方就会效率更慢。 你可能会问,到底什么时候协程会比线程慢,那就是非 io 密集型的任务,比如说只需要进行密集计算的任务。这种以计算为主要任务的程序,io 操作很少,io 操作当然就不会是线程的瓶颈了。起几个原生的线程去并发运算,自然比起几个协程的效率高,协程总是需要 CPU 去调度切换的,然而这种操作却是毫无价值。 |
![]() |
54
webcape233 1 天前 via iPhone
你说的这个资源硬还是计算密集型( cpu 密集)吧,如果一个线程对比一个协程,cpu 密集型下我想确实没有额外开销的更快
|
55
visper 20 小时 10 分钟前
当你有一百万个线程和一百万个协程的时候。
|
![]() |
56
OC0311 19 小时 21 分钟前
“总的来说是可以加快程序的运行效率” 你可能是知道原理的但是,这个回答确实是没回答到点上。感觉是想考察你对 goroutine 调度的理解。
|
57
zxjxzj9 18 小时 55 分钟前
理论上来说确实是的,因为携程就是在调度线程,既然是调度肯定有调度开销,最后理论上肯定是比原生慢。 但是实际上除非你是真的需要把 cpu 吃的超级满,否则对 web 端各种 1 核 docker 来说这俩是一模一样的
|
58
thevita 18 小时 47 分钟前
虽然我也问过类似的问题,但就冲说出 “非常耗费资源的操作”, 这面试官水平就不怎么样,什么叫消耗资源,啥资源啊
|
59
duoduoxu 18 小时 28 分钟前
goroutine 更便宜
https://en.wikipedia.org/wiki/Virtual_thread |
![]() |
60
la2la 18 小时 25 分钟前
在 Linux 系统中线程的切换是需要消耗资源的,那么最节省资源的线程调度算法就是
让线程在每个时间片之内都跑满这个时间不发生阻塞 在程序实际运行中这个算法是不可能实现的,总会有线程需要等到资源比如:IO 那么需要有一个比线程更小的调度单位就是协程 协程的本质就是一个代码块,类似于 todo 操作,在需要阻塞时,todo 到其他协程的开头代码运行,保证在线程时间片内不发生阻塞。 所以评价协程的收益需要看这个 Job 具体执行的任务,如果是纯计算的任务,那么最有效率的是独占 CPU ,其次是进程,线程。 在需要等待资源的 Job ,协程才有效率 |
![]() |
61
williamx 18 小时 24 分钟前
如果单纯的比较执行速度,当然是线程更快。但是协程轻量,占用资源少,简单。
所以,“不耗费资源的操作时,协程要更快,在耗费资源较多时,还是线程更快。”这个说法是完全错误的。 |
![]() |
62
jeffmingup 18 小时 20 分钟前
协程优势在上下文切换和初始化占用内存少上,适用于 io 密集场景( web ),可以开很多协程。cpu 密集场景上,一个协程对比一个线程就没啥优势了。
|
63
bbao 18 小时 7 分钟前
你可以反问他一句:用户态和内核态的区别,话题终结。
|
64
bbao 17 小时 51 分钟前
@bronyakaka
1 、goroutine 初始栈 2KB (会动态增长的,并不是说一定省内存了),而操作系统线程的栈通常 1MB 线程大小通常可以设置,但是也远比 2KB 要大; 缺点也有: 1 、没法控制怎么分配到 cpu 核上,开几个协程可能都挂一个线程上,,利用不了多核资源 GMP 模型的 M 就是利用了 Cpu 的资源,至于什么时候系统会额外的创造 M ,可以进一步了解 GMP 原理;你这第一个缺点不成立 3 、协程一旦执行阻塞系统调用,会把整个线程阻塞,导致该线程无法执行其他 goroutines ,降低并发效率 两个问题: 「 1 」,请问哪一个语言 (串行之行时,一旦阻塞了当前线程,当前线程后续还能之行动作) 「 2 」,当某个 G 被挂起,它仅会阻塞当前 G ,P 且会脱离 M ,自行寻找其他 M ,如果 M 此时不足且需要创建的话,会临时创建“M”,这恰好是优点 4 、协程不适合 CPU 密集型任务,因为没什么 io ,上下文切换反而增加了开销,,调度器也有损耗,不如用多线程直接绑定到核心上 |
![]() |
65
bronyakaka 17 小时 44 分钟前
@bbao #64 你第一、二点回复和我说的有矛盾吗? 3.2 临时创建 M 就没代价了?而且受还 GOMAXPROCS 限制,不就是降低并发效率。你是补充还是反驳?反驳也没反驳到点上啊 还是你没看懂我说的
|
66
bbao 17 小时 11 分钟前
@bronyakaka 看清了,降低并发性这部分:
我认为"在 IO 密集型业务中,哪怕存在 G 阻塞,M 挂起的行为时,Goroutine 的性能也是优秀的比线程并发强,所以它与自己比较,会降低并发行,但是这点对于其他线程并发场景,并不重要,本身就很高。" 也就不算缺点。 |
![]() |
67
lesismal 16 小时 23 分钟前
> thread 和 coroutine 最大的区别就是上下文切换是否自主可控。因为 thread 切换不可控,所以要应付数据一致性的地方比 coroutine 多得多。
@moudy #51 我感觉这没说到点子上,绝大多数应用层自己主动使用 go runtime.Gosched 也只是出让调度、业务逻辑本身并没有改变、runtime 调度回来后用户的逻辑代码还是那个执行顺序。 我觉得根本的点是 thread 、goroutine 的成本和数量、以及对应着是否需要用户主动操作实例(例如 conn )在多个 thread 或者多个 goroutine 之间的切换。 高在线业务,不可能为每个 conn 都创建一个 thread ,所以每个 conn 是在不同的 thread 中流转,比如处理网络的 io 线程池、cpu 消耗的 逻辑/worker 线程/线程池、数据库等其他基础设施的线程池,不同的线程池上下游之间要有 task 队列串联起来。用 thread 的语言和方案的框架封装和使用上更复杂,而且不能写同步代码。async await yield resume 那些手动档 coroutine 和 goroutine 、erlang 进程的自动挡是不一样的、远不如自动档方便。goroutine 和 erlang 进程轻量,每个连接一个、同步代码一把梭就完事了。 thread 方案对一致性的要求更高,goroutine/erlang 进程除非涉及连接之间的复杂交互之类的、否则不需要对一致性做太多麻烦的事情 |
![]() |
68
lesismal 16 小时 19 分钟前
我个人对这个面试双方的评价,不一定对:
1. OP 的编码主要是应用层,对基础知识不那么深入; 2. 面试官是杠精; 面试这种问题、如果候选人的回答已经反映出了 1 ,就没有必要像 2 这样纠结基础知识了: 1. 如果是招来做系统工程师之类的基础设施、底层研发,直接 pass 不考虑了,没必要继续杠 2. 如果是做 curd 之类的业务开发,了解这些基础知识也没用、只需要用来判定技术深度和技术等级、薪资就可以了,也没必要继续杠 |
![]() |
69
lxdlam 14 小时 47 分钟前
@w568w #9 如果你*每次*都使用 `launch(newSingleThreadContext()){}` 的话,它确实能被*认为*是一种线程的调度集合。但这只是 Kotlin 给出了底层调度的用户调优空间,Kotlin 的协程仍然是基于状态机的调度。
|
70
w568w 14 小时 29 分钟前
@lxdlam 是的。我举这些边界情况其实想说明的是每个人口中的「协程」可能都是不同的意思,因此最好不要随便使用这个已经被滥用的无效术语。就叫 用户线程/生成器/线程池 就好了。
|
![]() |
71
lxdlam 14 小时 29 分钟前
所有的 Coroutine ,无论有栈无栈还是夹在中间的什么混合模式,这个代码总是要被执行的。谁来执行呢?我援引 Solaris 最经典的 LWP 设计:
![]() 本质来说,从一个纯粹的 User program 或者被语言包裹好的这个"乌托邦"来看,OS Thread 就是新的 CPU Cores ,我们不妨叫他 Coroutine Process Unit ,其他的概念几乎等效,无非就是在这个新的 CPU Cores 上看这个新的调度器在做什么操作罢了;只不过我们有一个得天独厚的优势,就是这一切都发生在 User Space ,所有的 context switch 之类的操作都有很大空间不会切换到 Kernel Space ,也不需要跟特定 OS 信息交互,这样就能节省一大部分开销。通常认为的所谓 但是这能说明谁比谁更快吗?尝试用你的 workload 回答我下面三个问题: 1. 这个程序对 CPU 的 locality 要求有多高?无论是基于 NUMA 的同 Node 访问或者 Cache line 的访问优化,你需要它表现到什么样子? 2. 这个程序对 IO 的定制需求如何?一个 epoll/kqueue 就足够,还是需要 DMA/RDMA 这种需要外部 driver 交互的 IO 支持? Runtime 跟你的通信调度如何处理? 3. 这个程序的计算密集程度如何?是可以切成无互访的无状态并发,直接分发完数据 CPU 猛算,还是有高频的互访,实际上存在特定的通信效率瓶颈? 这三个问题只是一个例子,如何去考虑线程跟 Coroutine 的开销。大部分 Coroutine 退化到最后就是一堆普通的线程,插入了一些语言 Runtime 带来的额外钩子,这些钩子的成本显然随着 Coroutine 的增加会有所上升。 但是这个边际成本出现剧增的点在哪儿?不同 Workload 的答案不一样,拍脑袋得不出答案。不要想当然认为线程跟 coroutine 谁更好谁更快,做工程的要拿 benchmark 说话,而不是讨论假大空的概念。如果真对这个问题感兴趣,可以在一些 HPC 任务上跑跑 poc ,看看 HPC 工程师调 CPU Affinity 和 openmp 的观察和优化逻辑。 |
![]() |
72
lxdlam 14 小时 24 分钟前
@lxdlam #68 第二段漏了:通常认为的所谓 -> 通常认为的所谓 Coroutine 更快,建立在那些需要频繁 context switch 的任务上,比如最经典的就是 I/O polling 。
|
73
sampeng 13 小时 53 分钟前
大部分人讨论技术问题。其实是个人情世故。。。
|
![]() |
74
cenbiq 13 小时 40 分钟前
为什么会有线程和协程哪个快这样的问题?当然是线程执行更快啊。能说出协程更快的怕是连协程是干什么的都没搞明白,协程对于开发更好用是因为协程帮助开发者自动化的管理了线程的利用率和上下文切换时机。这对于高频 IO 类型的程序更加友好(尤其是对于做应用层开发而言),让人产生了协程更快的“错觉”,应该说协程让整体系统资源运行更协调,而不是更快。
|
![]() |
75
w0017 12 小时 25 分钟前
你是超级高并发业务吗?不是的话,别折腾了。
|