面试题
一、选择题
1.关于协程,下面说法正确是?
A. 协程和线程都可以实现程序的并发执行
B. 线程比协程更轻量级
C. 协程不存在死锁问题
D. 通过channel来进行协程间的通信
参考答案:AD
2.关于channel,下面语法正确的是()
A. var ch chan int
B. ch := make(chan int)
C. <- ch
D. ch <-
参考答案:ABC
D答案少了写入的数据:ch <- 3
3.关于同步锁,下面说法正确的是()
A. 当一个goroutine获得了Mutex后,其他goroutine就只能乖乖的等待,除非该goroutine释放这个Mutex
B. RWMutex在读锁占用的情况下,会阻止写,但不阻止读
C. RWMutex在写锁占用情况下,会阻止任何其他goroutine(无论读和写)进来,整个锁相当于由该goroutine独占
D. Lock()操作需要保证有Unlock()或RUnlock()调用与之对应
参考答案:ABC。Lock对应Unlock,RLock对应RUnlock
读写锁:
写锁:写写互斥,写读互斥
读锁:读读不互斥,读写互斥
4.关于channel的特性,下面说法正确的是()
A. 给一个 nil channel 发送数据,造成永远阻塞
B. 从一个 nil channel 接收数据,造成永远阻塞
C. 给一个已经关闭的 channel 发送数据,引起 panic
D. 从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值
参考答案:ABCD
5.关于 channel 下面描述正确的是?
A. 向已关闭的通道发送数据会引发 panic;
B. 从已关闭的缓冲通道接收数据,返回已缓冲数据或者零值;
C. 无论接收还是发送,nil 通道都会阻塞;
参考答案及解析:ABC。
6.关于无缓冲和有冲突的channel,下面说法正确的是()
A. 无缓冲的channel是默认的缓冲为1的channel // 默认位0
B. 无缓冲的channel和有缓冲的channel都是同步的
C. 无缓冲的channel和有缓冲的channel都是非同步的
D. 无缓冲的channel是同步的,而有缓冲的channel是非同步的
参考答案:D。
7.关于select机制,下面说法正确的是()
A. select机制用来处理异步IO问题
B. select机制最大的一条限制就是每个case语句里必须是一个IO操作
C. golang在语言级别支持select关键字
D. select关键字的用法与switch语句非常类似,后面要带判断条件
参考答案:ABC
8下面代码输出什么?请简要说明。
type MyMutex struct {
count int
sync.Mutex
}
func main() {
var mu MyMutex
mu.Lock()
var mu1 = mu
mu.count++
mu.Unlock()
mu1.Lock()
mu1.count++
mu1.Unlock()
fmt.Println(mu.count, mu1.count)
}
A. 不能编译;
B. 输出 1, 1;
C. 输出 1, 2;
D. fatal error;
参考答案及解析:D。加锁后复制变量,会将锁的状态也复制,所以 mu1 其实是已经加锁状态,再加锁会死锁。
代码优化后的:
func main() {
var mu MyMutex
mu.Lock()
mu.count++
mu.Unlock()
var mu1 = mu
mu1.Lock()
mu1.count++
mu1.Unlock()
fmt.Println(mu.count, mu1.count)
}
二、简答题
1.select是随机的还是顺序的?
随机的
2.协程,线程,进程的区别?
进程是资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元;
同一个进程中可以包括多个线程;
进程结束后它拥有的所有线程都将销毁,而线程的结束不会影响同个进程中的其他线程的结束;
线程共享整个进程的资源(寄存器、堆栈、上下文),一个进程至少包括一个线程;
线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源;
进程是资源分配的单位
线程是操作系统调度的单位
进程切换需要的资源很最大,效率很低 线程切换需要的资源一般,效率一般 协程切换任务资源很小,效率高 多进程、多线程根据cpu核数不一样可能是并行的 也可能是并发的。协程的本质就是使用当前进程在不同的函数代码中切换执行,可以理解为并行。 协程是一个用户层面的概念,不同协程的模型实现可能是单线程,也可能是多线程。
进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。(全局变量保存在堆中,局部变量及函数保存在栈中)
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是这样的)。
协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
一个应用程序一般对应一个进程,一个进程一般有一个主线程,还有若干个辅助线程,线程之间是平行运行的,在线程里面可以开启协程,让程序在特定的时间内运行。
协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。
3.说说go语言中的协程?
协程和线程都可以实现程序的并发执行;
通过channel来进行协程间的通信;
只需要在函数调用前添加go关键字即可实现go的协程,创建并发任务;
关键字go并非执行并发任务,而是创建一个并发任务单元;
4.说说go语言的channel特性?
给一个 nil channel 发送数据,造成永远阻塞
从一个 nil channel 接收数据,造成永远阻塞
给一个已经关闭的 channel 发送数据,引起 panic
从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值
无缓冲的channel是同步的,而有缓冲的channel是非同步的
5.说说go语言的select机制?
A. select机制用来处理异步IO问题
B. select机制最大的一条限制就是每个case语句里必须是一个IO操作
C. golang在语言级别支持select关键字
6.select可以用于什么?
常用于gorotine的完美退出
golang 的 select 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作
每个case语句里必须是一个IO操作,确切的说,应该是一个面向channel的IO操作
7.主协程如何等其余协程完再操作
sync.WiteGroup
Add() 指定计数器
Done() 计数器减1
Wite() 等待计数器减为0,结束
8.sync.Once的作用?实现一个单例
sync.Once 是 Golang package 中使方法只执行一次的对象实现,作用与 init 函数类似。但也有所不同。
init 函数是在文件包首次被加载的时候执行,且只执行一次
sync.Onc 是在代码运行中需要的时候执行,且只执行一次
当一个函数不希望程序在一开始的时候就被执行的时候,我们可以使用 sync.Once 。
9.死锁条件,如何避免?
死锁产生的原因
1.系统资源的竞争导致系统资源不足,以及资源分配不当,导致死锁
2.请求和释放资源的顺序不当,会导致死锁
如何避免:
channel推送和读取同时存在时才不会发生死锁,而且需要注意channel读写的顺序,只读或只推都会发生死锁