欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > 【Golang 面试题】每日 3 题(四十四)

【Golang 面试题】每日 3 题(四十四)

2025/4/19 10:08:24 来源:https://blog.csdn.net/Newin2020/article/details/145336478  浏览:    关键词:【Golang 面试题】每日 3 题(四十四)

✍个人博客:Pandaconda-CSDN博客
📣专栏地址:http://t.csdnimg.cn/UWz06
📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪

130. goroutine 阻塞、唤醒和退出状态

阻塞
channel 的读写操作、等待锁、等待网络数据、系统调用等都有可能发生阻塞,会调用底层函数 runtime.gopark(),会让出 CPU 时间片,让调度器安排其它等待的任务运行,并在下次某个时候从该位置恢复执行。

当调用该函数之后,goroutine 会被设置成 waiting 状态。

唤醒

处于 waiting 状态的 goroutine,在调用 runtime.goready() 函数之后会被唤醒,唤醒的 goroutine 会被重新放到 M 对应的上下文 P 对应的 runqueue 中,等待被调度。

当调用该函数之后,goroutine 会被设置成 runnable 状态。

退出

当 goroutine 执行完成后,会调用底层函数 runtime.Goexit()。

当调用该函数之后,goroutine 会被设置成 dead 状态。

131. Go goroutine 泄露原因

  • Goroutine 内进行 channel/mutex 等读写操作被一直阻塞。
  • Goroutine 内的业务逻辑进入死循环,资源一直无法释放。
  • Goroutine 内的业务逻辑进入长时间等待,有不断新增的 Goroutine 进入等待

132. Go goroutine 泄露场景

如果输出的 goroutines 数量是在不断增加的,就说明存在泄漏。

  1. nil channel
    channel 如果忘记初始化,那么无论你是读,还是写操作,都会造成阻塞。
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 intfor i := 0; i < 10; i++ {go func() {<-ch}()}
}

输出结果:

before goroutines:  1
after goroutines:  11
  1. 发送不接收

channel 发送数量超过 channel 接收数量,就会造成阻塞。

func block2() {ch := make(chan int)for i := 0; i < 10; i++ {go func() {ch <- 1}()}
}
  1. 接收不发送

channel 接收数量超过 channel 发送数量,也会造成阻塞。

func block3() {ch := make(chan int)for i := 0; i < 10; i++ {go func() {<-ch}()}
}
  1. http request body 未关闭
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()
  1. 互斥锁忘记解锁

第一个协程获取 sync.Mutex 加锁了,但是他可能在处理业务逻辑,又或是忘记 Unlock 了。
因此导致后面的协程想加锁,却因锁未释放被阻塞了。

func block5() {var mutex sync.Mutexfor i := 0; i < 10; i++ {go func() {mutex.Lock()}()}
}
  1. sync.WaitGroup 使用不当

由于 wg.Add 的数量与 wg.Done 数量并不匹配,因此在调用 wg.Wait 方法后一直阻塞等待。

func block6() {var wg sync.WaitGroupfor i := 0; i < 10; i++ {go func() wg.Add(2)wg.Done()wg.Wait()}()}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词