
本文深入探讨了 Go 语言并发程序中一个有趣的现象:当循环次数为奇数时,程序能够完整输出所有数值;而当循环次数为偶数时,最后一个数值却丢失。通过分析代码示例和调度器行为,揭示了并发程序中非确定性的本质,并强调了使用同步机制确保 Goroutine 完成的重要性。文章将帮助读者理解 Go 调度器的工作方式,并掌握编写可靠并发程序的关键技巧。
在 Go 语言中,并发编程是一项强大的特性,它允许程序同时执行多个任务。然而,并发也引入了非确定性,这意味着程序的行为可能因运行环境、调度器的决策等因素而异。本文将通过一个具体的例子,深入探讨 Go 调度器在并发程序中的行为,并解释为何循环次数的奇偶性会影响程序的输出结果。
问题描述
考虑以下 Go 代码:
package main
import "runtime"
func main() {
c2 := make(chan int)
go func() {
for v := range c2 {
println("c2 =", v, "numof routines:", runtime.NumGoroutine())
}
}()
for i := 1; i <= 10001; i++ {
c2 <- i
// runtime.Gosched()
}
}这段代码创建了一个 Goroutine,它从通道 c2 中接收整数并打印。主 Goroutine 向 c2 发送从 1 到 10001(或 10000)的整数。
令人惊讶的是,当循环次数为奇数(例如 10001)时,程序能够完整输出所有数值。但是,当循环次数为偶数(例如 10000)时,程序会丢失最后一个数值。
原因分析:调度器的非确定性
这种现象的根本原因是 Go 调度器的非确定性。当 main 函数返回时,程序会终止,而不会等待任何 Goroutine 完成。因此,Goroutine 是否能在 main 函数返回之前完成所有工作,取决于调度器的调度策略以及一些外部因素。
循环次数的奇偶性可能只是影响调度的一个因素。当循环次数为偶数时,可能由于某种巧合,调度器在 Goroutine 处理完所有数据之前就切换回了 main Goroutine,导致 main 函数提前返回,从而导致最后一个数值丢失。
解决方案:使用同步机制
为了确保 Goroutine 在 main 函数返回之前完成所有工作,我们需要使用同步机制。Go 提供了多种同步机制,例如 sync.WaitGroup。
以下是如何使用 sync.WaitGroup 修改代码以确保所有数值都被处理:
package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
c2 := make(chan int)
var wg sync.WaitGroup
wg.Add(1) // 增加计数器,表示有一个 Goroutine 需要等待
go func() {
defer wg.Done() // Goroutine 完成时减少计数器
for v := range c2 {
fmt.Println("c2 =", v, "numof routines:", runtime.NumGoroutine())
}
}()
for i := 1; i <= 10000; i++ {
c2 <- i
// runtime.Gosched()
}
close(c2) // 关闭通道,通知 Goroutine 没有更多数据了
wg.Wait() // 等待计数器归零,表示所有 Goroutine 都已完成
}在这个修改后的代码中,我们使用 sync.WaitGroup 来等待 Goroutine 完成。
通过使用 sync.WaitGroup,我们可以确保 main 函数在所有 Goroutine 完成工作后才返回,从而避免了数据丢失的问题。
总结
Go 调度器的非确定性是并发编程中需要注意的一个重要问题。为了编写可靠的并发程序,我们需要使用适当的同步机制来确保 Goroutine 在程序退出之前完成所有工作。sync.WaitGroup 是一个常用的同步机制,可以用于等待一组 Goroutine 完成。此外,使用 close 关闭channel也是通知goroutine不再有数据输入的重要手段。理解这些概念并正确应用它们,可以帮助我们编写出更加健壮和可靠的 Go 并发程序。
以上就是Go 调度器奇偶行为探究:并发程序中的非确定性与同步机制的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号