转自:http://blog.dccmx.com/2012/03/small-problem-about-goroutine/
goroutine是Go语言的标志性特性之一。配合channel,形成了Go语言处理并发的基础。但是,目前还有些小问题,或者说小不爽。就是会给你造成真并行的假象。
看下面的例子:
package main import ( "time" "runtime" ) func main () { ch := make(chan int) go func(ch chan int) { time.Sleep(1 * 1e9) ch <- 1 }(ch) go func(ch chan int) { for { select { case <-ch: println("got!!!") return default: println("waiting...") } } }(ch) time.Sleep(2 * 1e9) }
这里,我们的意图很明显,用一个goroutine做定时器,时间到了向channel发一信号,再用一个goroutine做事,收到信号后停止,最后一行sleep是为了防止main函数退出导致其他goroutine退出(为了省代码,这里不用channel同步了)。看起来天衣无缝,很是完美,惊叹一下Go的简洁优美。但是,运行之后会发现,一直输出waiting…,永远不会退出!
为什么??
因为Go语言现在的实现还不是很成熟,默认情况下,同时只有1个goroutine在跑,而当这个goroutine阻塞的时候,才会调度到其他的goroutine去,就像协程,不过这里由Go语言运行时帮你调度。
这个例子有三个解决方法。
1.在main函数里面第一行调用runtime.GOMAXPROCS(2)函数,将同时goroutine数设为2(或者更大),这个解决方法至少在我的双核机上跑是没问题的。1秒后就输出got!!!然后结束了。
2.制造阻塞,比如在println(“waiting…”)后面调用time.Sleep(1 * 1e8),这样输出10个waiting…后就got了。
3.手动切换,在println(“waiting…”)后面调用runtime.Gosched(),手动切换goroutine,这样也能结束。
这个问题很典型,初学者经常会中招,虽然从语义上讲,原始的做法并没有错,但是由于Go运行时还不够成熟(至少Go1看来是不打算解决了,以后会取消GOMAXPROCS改为自动判断),总之,大家小心点就好。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述