go

问答

go中的协程与线程的区别

协程(coroutine)是Go语言中的轻量级线程实现,由Go运行时(runtime)管理
参考 http://vinllen.com/gozhong-de-xie-cheng-goroutineyu-xian-cheng-de-qu-bie/
1 栈的大小(线程的栈有 8 MB,而go协程栈的大小通常只有 2~4 KB)
2 goroutine没有id
3 GOMAXPROCS
4 goroutine调度(上下文切换代价、由内核还是调度器完成、是否支持垃圾回收)

节省 CPU:避免系统内核级的线程频繁切换,造成的 CPU 资源浪费。好钢用在刀刃上。而协程是用户态的线程,用户可以自行控制协程的创建于销毁,极大程度避免了系统级线程上下文切换造成的资源浪费

节约内存:在 64 位的Linux中,一个线程需要分配 8MB 栈内存和 64MB 堆内存,系统内存的制约导致我们无法开启更多线程实现高并发。而在协程编程模式下,可以轻松有十几万协程,这是线程无法比拟的

稳定性:前面提到线程之间通过内存来共享数据,这也导致了一个问题,任何一个线程出错时,进程中的所有线程都会跟着一起崩溃

开发效率:使用协程在开发程序之中,可以很方便的将一些耗时的IO操作异步化,例如写文件、耗时 IO 请求等

进程、线程、协程的关系和区别:
进程是操作系统对一个正在运行的程序的一种抽象,进程是资源分配的最小单位
进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。

线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。
线程比进程之间更容易共享数据,在上下文切换中线程一般比进程更高效(创建线程比创建进程要快)

协程(Coroutine)是用户态的线程。通常创建协程时,会从进程的堆中分配一段内存作为协程的栈
协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。

为什么协程比线程轻量

参考 https://studygolang.com/articles/21716
1 go协程调用跟切换比线程效率高
2.go协程占用内存少

Go的CSP并发模型

参考 https://www.cnblogs.com/sunsky303/p/9115530.html(重点)
Go实现了两种并发形式。第一种是大家普遍认知的:多线程共享内存。其实就是Java或者C++等语言中的多线程开发。另外一种是Go语言特有的,也是Go语言推荐的:CSP(communicating sequential processes)并发模型。
普通的线程并发模型,就是像Java、C++、或者Python,他们线程间通信都是通过共享内存的方式来进行的。Go的CSP并发模型,是通过goroutine和channel来实现的。

Go调度器

参考 https://juejin.im/post/5ce11a39f265da1baf7cbc61
go协程也叫用户态线程
CSP并发模型实现:M, P, G :go调度里面有三个角色:M代表内核线程,P代表上下文,G代表协程
img

Golang中的struct能不能比较

不管是不是同一个struct对象的对象进行比较, 可以能,也可以不能
可排序的数据类型有三种,Integer,Floating-point,和String
可比较的数据类型除了上述三种外,还有Boolean,Complex,Pointer,Channel,Interface和Array
不可比较的数据类型包括,Slice, Map, 和Function
参考 https://studygolang.com/articles/27045

go defer

Go 语言的 defer 会在当前函数或者方法返回之前执行传入的函数。它会经常被用于关闭文件描述符、关闭数据库连接以及解锁资源。执行顺序先进后出

defer 与 recover函数配合 实现类似java的 try catch功能

select可以用于什么(select 的用法)

参考 https://www.jianshu.com/p/83fc5dcd2f83
select 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作
没有default select语句会一直等待,直到某个case里的IO操作可以进行
channel求值顺序:自上而下、从左到右
如果有多个case同时可以运行,go会随机选择一个case执行
使用break终止select语句的执行

context包的用途

参考 https://geektutu.com/post/quick-go-context.html
通知子协程退出(正常退出,超时退出等)
传递必要的参数。

slice的len,cap,共享,扩容

参考 https://blog.csdn.net/u013474436/article/details/88770501
切片的长度和容量不同,长度表示左指针至右指针之间的距离,容量表示左指针至底层数组末尾的距离。
切片的扩容机制,append的时候,如果长度增加后超过容量,则将容量增加2倍,同时变换了底层数组。
切片append机制,是把slice后边数据逐个覆盖写入。
切片copy机制,按其中较小的那个数组切片的元素个数进行复制。

sync包的应用详解

参考 https://mp.weixin.qq.com/s/Qti6dCgNqwlnK0eyEDeYew
sync.Mutex
sync.RWMutex
sync.WaitGroup
sync.Map
sync.Pool
sync.Once
sync.Cond

go channel的原理

参考 https://www.jianshu.com/p/d841f251d3bc

go语言中new和make的区别

new(T)创建一个没有任何数据的类型为T的实例,并返回该实例的指针;
make(T, args)只能创建 slice、map和channel,并且返回一个有初始值args(非零)的T类型的实例,非指针。
二者都是内存的分配(堆上),但是make只用于slice、map以及channel的初始化(非零值);而new用于类型的内存分配,并且内存置为零。

go程序如何编译为机器码

参考 https://baijiahao.baidu.com/s?id=1617651814280074562&wfr=spider&for=pc
编译器的三个阶段:
扫描程序,将源代码转换为令牌列表,供解析器使用。
解析器,将标记转换为抽象语法树,供代码生成使用。
代码生成,将抽象语法树转换为机器代码。

Go的runtime

参考 https://studygolang.com/articles/10114

Go的垃圾回收器

参考 https://blog.csdn.net/u010649766/article/details/80582153
三色标记法
https://www.cnblogs.com/wangyiyang/p/12191591.html