如何让 Go 程序正确并发执行 goroutine 与主循环
技术百科
碧海醫心
发布时间:2026-01-22
浏览: 次 go 程序中若在 `main` 函数末尾使用空 `for{}` 死循环,会导致调度器无法切换到其他 goroutine;根本原因在于该循环不触发调度点,新启动的 goroutine 来不及被调度即被“饿死”。解决方法是插入调度让点(如 `time.sleep`)或改用阻塞式等待(如 `select{}`)。
在 Go 中,并发调度依赖于协作式调度机制:goroutine 只有在发生系统调用、通道操作、time.Sleep、runtime.Gosched() 或函数调用(可能引发栈增长/检查)等调度点(schedul 
你提供的代码存在一个典型误区:
func main() {
runtime.GOMAXPROCS(runtime.NumCPU() * 8) // ✅ 设置最大 OS 线程数(但非必需)
go func() {
for {
time.Sleep(1 * time.Second)
fmt.Println("From routine")
}
}()
for {} // ❌ 危险!无限空循环 —— 无调度点、不释放 CPU、不触发 GC 检查、完全阻塞当前 M/P
}尽管 GOMAXPROCS 控制了可并行执行的 OS 线程上限(影响 CPU 密集型任务的并行度),但它不能绕过调度器的基本规则。问题核心并非线程数量不足,而是 for{} 导致 main goroutine 永不交出控制权,调度器根本没有机会将后台 goroutine 分配到其他线程(甚至同一 P 上)执行——它甚至可能还没来得及被放入运行队列。
✅ 正确做法一:插入轻量级调度让点
在死循环前添加微小休眠,确保 goroutine 已启动且调度器有机会介入:
func main() {
runtime.GOMAXPROCS(runtime.NumCPU() * 8)
go func() {
for i := 0; i < 5; i++ {
time.Sleep(1 * time.Second)
fmt.Println("From goroutine:", i)
}
}()
time.Sleep(time.Millisecond) // ✅ 关键:让出当前时间片,触发调度
for {} // 此时后台 goroutine 极大概率已开始运行
}⚠️ 注意:time.Sleep(time.Millisecond) 并非“必须 1ms”,任何非零 Sleep(如 1ns)均可触发调度;但实践中建议 ≥1ms 以兼顾可靠性和精度。
✅ 更优做法二:使用 select{} 阻塞等待(推荐)
select{} 在无 case 可选时会永久阻塞,且完全不消耗 CPU,同时保持调度器活跃,是等待 goroutine 完成的标准惯用法:
func main() {
// GOMAXPROCS 可省略(默认已是 NumCPU)
go func() {
for i := 0; i < 5; i++ {
time.Sleep(1 * time.Second)
fmt.Println("From goroutine:", i)
}
}()
select {} // ✅ 完美阻塞:零 CPU 占用,允许所有 goroutine 公平调度
}? 补充说明:
- LockOSThread() 在此场景无效且有害:它将 main goroutine 绑定到某个 OS 线程,反而限制了调度灵活性,且空循环仍会独占该线程。
- GOMAXPROCS 对 I/O 密集型 goroutine(如含 time.Sleep、网络请求)影响有限,其主要价值在于提升 CPU 密集型任务的并行吞吐。
- 若需等待多个 goroutine 结束,应使用 sync.WaitGroup + select{} 或带超时的 time.After,而非轮询或空循环。
总结:Go 的并发模型建立在合作调度之上,编写无调度点的纯计算死循环(for{})是反模式。始终优先选用 select{}、time.Sleep、通道阻塞等内置调度友好的原语,才能真正释放 Go 调度器的强大能力。
# ai
# 可选
# 多个
# 解决方法
# 但它
# 才会
# 在此
# 均可
# 而非
# 已是
# 有机会
# 还没
# go
# 循环
# 并发
# 线程
# 栈
# select
# for
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- php转exe用什么工具打包快_高效打包软件推荐【
- Win11怎么关闭通知中心_Windows11系统
- Win11 explorer.exe频繁崩溃_修复
- 如何在Golang中实现CI/CD流水线自动化测试
- Windows如何拦截2345弹窗广告_Windo
- 如何在Golang中写入XML文件_生成符合规范的
- Dapper的Execute方法的返回值是什么意思
- 如何使用Golang defer优化性能_减少不必
- Windows10如何更改计算机工作组_Win10
- Go 语言标准库为何不提供泛型 Contains
- Win11屏幕亮度突然变暗怎么解决_自动变暗问题处
- Win11如何设置文件关联 Win11修改特定文件
- 如何用::实现单例模式_php静态方法与作用域操作
- c++怎么处理多线程死锁_c++ lock_gua
- c++ namespace命名空间用法_c++避免
- 如何在Golang中处理数据库事务错误_回滚和日志
- 如何用列表一次性对 DataFrame 的指定列应
- 如何在 Go 中正确反序列化多个同级 XML 元素
- 如何使用Golang理解结构体指针方法接收者_Go
- Windows 10怎么把任务栏放在屏幕上方_Wi
- Windows任务计划服务异常原因_任务调度失败的
- Win11怎么把图标拖到任务栏_Win11固定应用
- php订单日志怎么导出excel_php导出订单日
- Windows10电脑怎么连接蓝牙设备_Win10
- php删除数据怎么清空表_truncate与del
- c++怎么用jemalloc c++替换默认内存分
- Mac怎么设置登录项_Mac管理开机自启动程序【教
- LINUX怎么查看进程_LINUX ps命令查看运
- c# 如何用c#实现一个支持优先级的任务队列
- Windows10怎么备份注册表_Windows1
- Win11怎么设置快速访问_Windows11文件
- Mac如何解压zip和rar文件?(推荐免费工具)
- c++的位运算怎么用 与、或、异或、移位操作详解【
- Mac如何创建和管理多个桌面空间_Mac高效多任务
- 如何在Golang中定义接口_抽象方法和多态实现
- C#怎么使用委托和事件 C# delegate与e
- 如何使用Golang开发简单的聊天室消息存储_Go
- Python正则表达式实战_模式匹配说明【教程】
- Mac的Time Machine怎么用_Mac系统
- c# 在高并发下使用反射发射(Reflection
- Mac版Final Cut Pro入门_Mac视频
- PHP主流架构怎么处理表单验证_规则与自定义【技巧
- Windows服务持续崩溃怎样修复_系统服务保护机
- Mac电脑进水了怎么办_MacBook进水后紧急处
- 如何使用Golang实现负载均衡_分发请求到多个服
- Win10怎么卸载迅雷_Win10彻底卸载迅雷方法
- 用lighttpd能运行php吗_lighttpd
- Python数据抓取合法性_合规说明【指导】
- php下载安装包怎么选_threadsafe与nt
- Win11任务栏颜色怎么改_Win11自定义任务栏

QQ客服