值得一看
广告
彩虹云商城
广告

热门广告位

Go 并发编程中的 Goroutine 调度与阻塞问题

go 并发编程中的 goroutine 调度与阻塞问题

本文探讨了 Go 并发编程中一个常见的“海森堡 Bug”,即在某些情况下,向标准输出打印内容会导致程序行为发生改变。通过分析一个模拟理发师问题的示例,解释了 Go 调度器的运作机制,以及如何通过更合理的方式进行非阻塞的 channel 操作,避免潜在的竞争条件。

在 Go 语言的并发编程中,Goroutine 的调度是一个核心概念。理解 Goroutine 的调度方式对于编写高效且可靠的并发程序至关重要。一个常见的困惑是,为什么在一段并发代码中添加 fmt.Println 语句后,程序的行为会发生改变,甚至从阻塞状态恢复正常?

Goroutine 调度机制

Go 语言的调度器负责在多个 Goroutine 之间分配 CPU 时间。Goroutine 只有在进行系统调用或者阻塞的 channel 操作时,才会让出 CPU 的执行权。fmt.Println 函数会触发系统调用,这使得当前 Goroutine 有机会让出 CPU,让其他 Goroutine 获得执行机会。

在没有 fmt.Println 的情况下,如果某个 Goroutine 一直在执行计算密集型任务,而没有进行任何阻塞操作,那么它可能会一直占用 CPU,导致其他 Goroutine 无法得到执行。这可能导致程序出现“饿死”现象,即某些 Goroutine 永远无法运行。

示例:理发师问题

考虑一个简化的理发师问题:

package main
import "fmt"
func customer(id int, shop chan<- int) {
// 进入理发店,如果还有座位,否则离开
// fmt.Println("取消注释这行代码,程序就能正常工作")
if len(shop) < cap(shop) {
shop <- id
}
}
func barber(shop <-chan int) {
// 为进入理发店的顾客理发
for {
fmt.Println("理发师为顾客", <-shop, "理发")
}
}
func main() {
shop := make(chan int, 5) // 五个座位
go barber(shop)
for i := 0; ; i++ {
customer(i, shop)
}
}

在这个例子中,customer 函数模拟顾客进入理发店,如果理发店有空位,则将顾客 ID 发送到 shop channel 中。barber 函数模拟理发师,从 shop channel 中接收顾客 ID 并为其理发。

如果没有注释掉 customer 函数中的 fmt.Println 语句,程序可以正常运行。但是,如果注释掉该语句,barber 函数可能永远无法接收到顾客 ID,导致程序阻塞。

这是因为 customer 函数在没有 fmt.Println 的情况下,可能会一直快速地向 shop channel 发送顾客 ID,而 barber 函数没有机会从 shop channel 中接收顾客 ID。当 shop channel 满时,customer 函数会阻塞,但由于 barber 函数没有机会运行,因此 shop channel 永远无法被清空,导致程序死锁。

更安全的非阻塞 Channel 操作

在 customer 函数中使用 len(shop) < cap(shop) 判断 channel 是否已满存在潜在的竞争条件。在判断之后,channel 可能已经被其他 Goroutine 填满。为了更安全地进行非阻塞的 channel 发送,可以使用 select 语句:

func customer(id int, shop chan<- int) {
// 进入理发店,如果还有座位,否则离开
select {
case shop <- id:
default:
}
}

select 语句会尝试向 shop channel 发送顾客 ID。如果 shop channel 已满,则会执行 default 分支,而不会阻塞。这种方式更加安全,可以避免潜在的竞争条件。

总结

理解 Go 语言的 Goroutine 调度机制对于编写健壮的并发程序至关重要。fmt.Println 语句看似无害,但实际上会影响 Goroutine 的调度。在编写并发程序时,需要注意避免长时间占用 CPU 的计算密集型任务,并使用更安全的方式进行非阻塞的 channel 操作,以避免潜在的竞争条件和死锁。

温馨提示: 本文最后更新于2025-08-31 22:28:24,某些文章具有时效性,若有错误或已失效,请在下方留言或联系在线客服
文章版权声明 1 本网站名称: 创客网
2 本站永久网址:https://new.ie310.com
1 本文采用非商业性使用-相同方式共享 4.0 国际许可协议[CC BY-NC-SA]进行授权
2 本站所有内容仅供参考,分享出来是为了可以给大家提供新的思路。
3 互联网转载资源会有一些其他联系方式,请大家不要盲目相信,被骗本站概不负责!
4 本网站只做项目揭秘,无法一对一教学指导,每篇文章内都含项目全套的教程讲解,请仔细阅读。
5 本站分享的所有平台仅供展示,本站不对平台真实性负责,站长建议大家自己根据项目关键词自己选择平台。
6 因为文章发布时间和您阅读文章时间存在时间差,所以有些项目红利期可能已经过了,能不能赚钱需要自己判断。
7 本网站仅做资源分享,不做任何收益保障,创业公司上收费几百上千的项目我免费分享出来的,希望大家可以认真学习。
8 本站所有资料均来自互联网公开分享,并不代表本站立场,如不慎侵犯到您的版权利益,请联系79283999@qq.com删除。

本站资料仅供学习交流使用请勿商业运营,严禁从事违法,侵权等任何非法活动,否则后果自负!
THE END
喜欢就支持一下吧
点赞10赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容