golang 面试之协程比线程更轻量级?

2020 年 6 月 4 日
 xmge

最近在 golang 面试,一般都会设计到为什么 go 语言更好地支持高并发,

答:在高并发场景下,创建一个协程比创建一个线程消耗的资源少很多,一般线程创建需要 8Mb,而协程只需要 2kb,所以在同性能的服务器下,协程可以支持更多的并发量。

有的面试官就会问:协程比线程为什么少占这么多资源?

h 在网上搜索相关文章,并没有找到很直接,很具体的说法,

是不是只有我一个人不知道啊,望知道的大佬给普及下,感谢....

8604 次点击
所在节点    程序员
42 条回复
gimp
2020 年 6 月 5 日
线程运行在进程中,协程运行在线程中。
ipwx
2020 年 6 月 5 日
因为切换线程是内核管的,要存储 /恢复一堆上下文。因为线程是通用的模型,所以操作系统内核为了不出错,会比知道更多程序运行细节的 go 编译器做更多的备份 /还原操作。另外切换线程进内核是需要中断触发的,又是一套比较复杂的流程。
ipwx
2020 年 6 月 5 日
@hercule 肯定是内核态用户态啊。协程是 go 模拟出来的,一堆协程运行在同一个线程上,Go 因为知道更多程序运行信息,不需要做 overkill 的上下文备份 /还原,上下文开销自然就小了。而且不用过中断,不用进内核(进内核需要改 CPU 特权等级,有不少操作要做),省了太多事情。
129tyc
2020 年 6 月 5 日
答案很简单,因为线程创建会分配更大的调用栈空间,比如 linux 下可以是 10M,而 go 协程创建默认的调用栈大小是 2K
justicelove
2020 年 6 月 5 日
就是内核线程和用户线程的区别, java1.2 之前也是用户线程,后来改成了内核线程
BingoXuan
2020 年 6 月 5 日
现实当中,裸机跑程序效率最高的。加入 OS 这么方便的一层后效率就低很多了。所以要高效最好不要让操作系统重新调度资源。因而在操作系统最小调度单位线程下,通过协程做并发处理好过用操作系统线程调度。如果进程是厂房,线程是流水线,那么协程流水线自动适应生产不同产品,避免闲置流水线或新建流水线来生产。让 n 条流水线生产出 m 种产品( m>n )。
ylsc633
2020 年 6 月 5 日
你这个问题 我去某大厂面试也被问到! 一模一样的! 可惜当时我并没有看过也不记得操作系统相关

emmmm.. 现在也没怎么看,就看了一些大佬关于 gmp 的!

然后根据文章 汇总了一篇文章

http://interview.wzcu.com/Golang/goroutine.html#goroutine-%E5%92%8C-thread-%E7%9A%84%E5%8C%BA%E5%88%AB

希望对你有帮助(里面还有上百套笔试题,很多都是我面试亲自遇到收集的)! 另外, 我的想法是 还是得深入研究下 操作系统..(毕业多年,已完全忘光)
ylsc633
2020 年 6 月 5 日
对了 记得看下这个概念 http://interview.wzcu.com/Golang/morestack.html
keshawnvan
2020 年 6 月 5 日
1.堆栈刚开始比较小
2.比起线程去掉了线程局部存储
fiypig
2020 年 6 月 5 日
@ylsc633 大佬可以的 ,收藏起来了
Philippa
2020 年 6 月 5 日
大家看看第一个回答的视频,一个个技术要求来不断进化设计,看 20 分钟就好了,后面太多细节。就是那貌似是俄语口音的英语也只有自动英语字幕,不容易听。
mengzhuo
2020 年 6 月 5 日
1. 线程没这么多,一个 Goroutine 现在是 384 字节
2. 轻量是因为,线程上下文切换不仅大,还需要 flush TBL
haha370104
2020 年 6 月 5 日
本质上就是单线程,我的个人理解是 runtime 机制带来的程序内的控制权转交
6ufq0VLZn0DDkL80
2020 年 6 月 5 日
@mengzhuo 同进程的线程切换为什么要刷 tlb,而且新一些的 cpu 上有 asid 不用把 tlb 全刷掉了。
yukiloh
2020 年 6 月 5 日
一楼一上来是个空白,吓了我一跳..
mengzhuo
2020 年 6 月 5 日
@cholerae 搞错哈,现在不用刷的话性能应该没有什么区别了吧。
liuxingdeyu
2020 年 6 月 5 日
在想一个问题,是不是还有个原因,就是协程使用的时间成本相对小于线程,因为协程的时间粒度更小
lff0305
2020 年 6 月 5 日
@sagaxu 没这么大, C/C++ call createThread api 的时候可以设置栈大小, 默认好像是 1M
早几年记得 Java 好像是 512k 默认, 后来改成 128k 了 (可以用 -Xss 设置)
xsen
2020 年 6 月 5 日
1. 协程是轻量级的线程,就是说资源占用少很多

2. 可以认为协程是用户态的轻量级线程,不会涉及到上下文切换——那自然效率更高、性能更好
这个类似用户态的网络协议栈,一样的道理

其实从模型上来说,协程的底层机制类似基于 mq 的任务分发机制;只是协程底层针对一般的 mq 任务分发,多做了一层虚拟资源的调度中心(调度逻辑 cpu 资源)
xsen
2020 年 6 月 5 日
也就是把一个线程当成一个逻辑 cpu,然后 go 做了一个基于时间片的调度中心,最小任务是协程
因为都是在用户态(单个线程),所以资源消耗比线程小,没有上下文切换

所以性能可以更好

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

https://v2ex.ih06.com/t/678713

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

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

© 2021 V2EX