✍个人博客:Pandaconda-CSDN博客
专栏地址:http://t.csdnimg.cn/UWz06
专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞收藏,您的支持就是我创作的最大动力
阻塞
channel 的读写操作、等待锁、等待网络数据、系统调用等都有可能发生阻塞,会调用底层函数 runtime.gopark(),会让出 CPU 时间片,让调度器安排其它等待的任务运行,并在下次某个时候从该位置恢复执行。
当调用该函数之后,goroutine 会被设置成 waiting 状态。
唤醒
处于 waiting 状态的 goroutine,在调用 runtime.goready() 函数之后会被唤醒,唤醒的 goroutine 会被重新放到 M 对应的上下文 P 对应的 runqueue 中,等待被调度。
当调用该函数之后,goroutine 会被设置成 runnable 状态。
退出
当 goroutine 执行完成后,会调用底层函数 runtime.Goexit()。
当调用该函数之后,goroutine 会被设置成 dead 状态。
如果输出的 goroutines 数量是在不断增加的,就说明存在泄漏。
func main() {
fmt.Println("before goroutines: ", runtime.NumGoroutine())
block1()
time.Sleep(time.Second * 1)
fmt.Println("after goroutines: ", runtime.NumGoroutine())
}
func block1() {
var ch chan int
for i := 0; i < 10; i++ {
go func() {
<-ch
}()
}
}
输出结果:
before goroutines: 1
after goroutines: 11
channel 发送数量超过 channel 接收数量,就会造成阻塞。
func block2() {
ch := make(chan int)
for i := 0; i < 10; i++ {
go func() {
ch <- 1
}()
}
}
channel 接收数量超过 channel 发送数量,也会造成阻塞。
func block3() {
ch := make(chan int)
for i := 0; i < 10; i++ {
go func() {
<-ch
}()
}
}
resp.Body.Close() 未被调用时,goroutine 不会退出。
func requestWithNoClose() {
_, err := http.Get("https://www.baidu.com")
if err != nil {
fmt.Println("error occurred while fetching page, error: %s", err.Error())
}
}
func requestWithClose() {
resp, err := http.Get("https://www.baidu.com")
if err != nil {
fmt.Println("error occurred while fetching page, error: %s", err.Error())
return
}
defer resp.Body.Close()
}
func block4() {
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
requestWithNoClose()
}()
}
}
var wg = sync.WaitGroup{}
func main() {
block4()
wg.Wait()
}
一般发起 http 请求时,需要确保关闭 body。
defer resp.Body.Close()
第一个协程获取 sync.Mutex 加锁了,但是他可能在处理业务逻辑,又或是忘记 Unlock 了。
因此导致后面的协程想加锁,却因锁未释放被阻塞了。
func block5() {
var mutex sync.Mutex
for i := 0; i < 10; i++ {
go func() {
mutex.Lock()
}()
}
}
由于 wg.Add 的数量与 wg.Done 数量并不匹配,因此在调用 wg.Wait 方法后一直阻塞等待。
func block6() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
go func()
wg.Add(2)
wg.Done()
wg.Wait()
}()
}
}