Golang中关于https://play.golang.org/p/FCydAiNZNWv的一些疑问
Golang中关于https://play.golang.org/p/FCydAiNZNWv的一些疑问 https://play.golang.org/p/FCydAiNZNWv
我不理解这个:time.Sleep(time.Second * 2)
我不理解这个:runtime.Gosched() // 告诉运行时将处理器让给其他 goroutine
“counter” 是什么?
cherilexvold1974:
time.Sleep(time.Second * 2)
你好,Cherolyn,根据这部分代码被注释掉,然后紧接着是 runtime.Gosched() 的情况,我的印象是,写这段代码的人试图强制一个 goroutine 进入休眠状态,以便另一个 goroutine 能够运行。counter 是一个全局变量,在那个 for 循环中创建的 goroutines 正在递增它。
不过,如果没有更多的上下文,我不太确定这段代码本意是要做什么或者演示什么。
time.Sleep(time.Second * 2)
更多关于Golang中关于https://play.golang.org/p/FCydAiNZNWv的一些疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
time.Sleep(time.Second * 2) 的作用是让 goroutine 暂停 2 秒。不过它已经被注释掉了。它的副作用是会让其他 goroutine 得以运行。
runtime.Gosched() 告诉运行时暂停当前 goroutine,让其他 goroutine 运行。这是一种特殊的暂停,因为其他 goroutine 将会运行。它完成所需的时间远少于 2 秒。
counter 是一个会被递增的全局变量。
我猜这段代码是为了演示并发递增计数器的效果。在这段代码中,有一个互斥锁保护着递增操作。由于互斥锁的存在,只有一个 goroutine 可以执行 Lock 和 Unlock 之间的代码。最终的结果是,计数器的最终值将是 gs 的值。
如果没有互斥锁的 Lock 和 Unlock,计数器的值将会不同(小于 gs)。
这个代码演示了goroutine并发访问共享变量时的竞态条件问题。让我逐一解释:
package main
import (
"fmt"
"runtime"
"time"
)
var counter int // counter是一个全局整型变量,被多个goroutine共享访问
func main() {
runtime.GOMAXPROCS(2) // 设置使用2个CPU核心
go incCounter(1) // 启动第一个goroutine
go incCounter(2) // 启动第二个goroutine
time.Sleep(time.Second * 2) // 主goroutine休眠2秒,等待其他goroutine执行
fmt.Printf("Final Counter: %d\n", counter)
}
func incCounter(id int) {
for count := 0; count < 2; count++ {
value := counter // 读取counter当前值
runtime.Gosched() // 主动让出CPU,让其他goroutine运行
value++ // 增加本地副本的值
counter = value // 写回全局变量
fmt.Printf("Goroutine %d: Counter = %d\n", id, counter)
}
}
关于time.Sleep(time.Second * 2):
这是为了让主goroutine等待其他goroutine完成。如果没有这个等待,主goroutine会立即结束,程序退出,其他goroutine可能来不及执行。
关于runtime.Gosched():
这个调用主动让出当前goroutine的CPU时间片,让调度器可以运行其他goroutine。在这个例子中,它故意制造竞态条件,让两个goroutine交替执行,更容易观察到数据竞争。
关于counter:
counter是一个全局共享变量,两个goroutine都会对它进行读取、修改、写入操作。由于没有同步机制,会出现以下竞态情况:
可能的执行顺序:
- Goroutine1读取counter=0
- Goroutine1让出CPU
- Goroutine2读取counter=0
- Goroutine2让出CPU
- Goroutine1写入counter=1
- Goroutine2写入counter=1(覆盖了Goroutine1的结果)
最终counter可能是2(理想情况),也可能是1(发生了数据竞争)。
要修复这个问题,应该使用同步原语如mutex:
var (
counter int
mutex sync.Mutex
)
func incCounter(id int) {
for count := 0; count < 2; count++ {
mutex.Lock()
value := counter
value++
counter = value
mutex.Unlock()
fmt.Printf("Goroutine %d: Counter = %d\n", id, counter)
}
}

