Golang为什么会出现打印不同步的问题

Golang为什么会出现打印不同步的问题 我正在学习Go语言。正在阅读一本书,其中包含以下代码:

// This sample program demonstrates how to create goroutines
package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

// wg is used to wait for the program to finish goroutines.
var wg sync.WaitGroup

func main() {
	// Add a count of two, one for each goroutine.
	wg.Add(2)
	fmt.Println("Start Goroutines")
	//launch a goroutine with label "A"
	go printCounts("A")
	//launch a goroutine with label "B"
	go printCounts("B")
	// Wait for the goroutines to finish.
	fmt.Println("Waiting To Finish")
	wg.Wait()
	fmt.Println("\nTerminating Program")
}
func printCounts(label string) {
	// Schedule the call to WaitGroup's Done to tell we are done.
	defer wg.Done()
	// Randomly wait
	for count := 1; count <= 10; count++ {
		sleep := rand.Int63n(1000)
		time.Sleep(time.Duration(sleep) * time.Millisecond)
		fmt.Printf("Count: %d from %s\n", count, label)
	}
}

产生以下结果: 启动协程 等待完成 计数:1 来自 A 计数:1 来自 B 计数:2 来自 B 计数:2 来自 A 计数:3 来自 B 计数:3 来自 A 计数:4 来自 A 计数:5 来自 A 计数:4 来自 B 计数:6 来自 A 计数:5 来自 B 计数:7 来自 A 计数:6 来自 B 计数:7 来自 B 计数:8 来自 A 计数:8 来自 B 计数:9 来自 B 计数:9 来自 A 计数:10 来自 A 计数:10 来自 B

终止程序

我的问题是为什么从计数4开始就不同步了?为什么不像1、2、3那样连续打印?因为从8开始又按顺序打印了。


更多关于Golang为什么会出现打印不同步的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

谢谢

更多关于Golang为什么会出现打印不同步的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


但每次都是相同的情况,为什么 Go 调度器在 3 之后跳过一个,然后在 8 处恢复正常?

这取决于 Go 调度器如何调度各个 goroutine。sync.WaitGroup 仅确保完成一组 goroutine 的执行。

wait() 只是一个阻塞调用,直到等待组计数器变为零。

因为每次生成的随机暂停间隔都是相同的:

顶层函数(如 Float64 和 Int)使用默认共享源,每次程序运行时都会生成确定性的值序列。

每次都需要使用不同的种子。调度器参与序列的生成方式,这只是因为你的"随机"暂停时长导致的。

在Go语言中,打印不同步是由于goroutine的并发执行特性导致的。每个goroutine独立运行,调度器在不同线程间切换时,执行顺序是不确定的。虽然代码中使用了随机休眠来模拟实际场景,但即使没有休眠,输出顺序也可能因调度而不同步。

具体到你的代码:

  • 两个goroutine AB 同时运行,各自循环打印计数1到10。
  • 每次循环中,它们随机休眠0到999毫秒,这导致它们的执行进度不同。
  • 在计数1、2、3时,可能由于休眠时间相近,输出看起来连续;但从计数4开始,休眠时间的差异累积,导致打印顺序交错。
  • 在计数8时,可能又因休眠时间巧合,输出顺序恢复同步,但这完全是随机的。

示例代码中,fmt.Printf 操作不是原子性的,多个goroutine同时调用时,输出可能交织。即使没有休眠,Go调度器也可能在任意点切换goroutine,导致打印顺序不确定。

以下是一个简化示例,展示即使没有休眠,打印也可能不同步:

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func main() {
	wg.Add(2)
	go printCounts("A")
	go printCounts("B")
	wg.Wait()
}

func printCounts(label string) {
	defer wg.Done()
	for count := 1; count <= 5; count++ {
		fmt.Printf("Count: %d from %s\n", count, label)
	}
}

运行此代码多次,输出顺序可能每次不同,例如:

Count: 1 from A
Count: 1 from B
Count: 2 from A
Count: 2 from B
Count: 3 from A
Count: 3 from B
Count: 4 from A
Count: 4 from B
Count: 5 from A
Count: 5 from B

或:

Count: 1 from B
Count: 1 from A
Count: 2 from B
Count: 2 from A
Count: 3 from B
Count: 3 from A
Count: 4 from B
Count: 4 from A
Count: 5 from B
Count: 5 from A

要确保同步打印,需使用同步机制如互斥锁(mutex),例如:

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup
var mu sync.Mutex

func main() {
	wg.Add(2)
	go printCounts("A")
	go printCounts("B")
	wg.Wait()
}

func printCounts(label string) {
	defer wg.Done()
	for count := 1; count <= 5; count++ {
		mu.Lock()
		fmt.Printf("Count: %d from %s\n", count, label)
		mu.Unlock()
	}
}

这样,输出会按goroutine顺序完成,但整体顺序仍可能交错,除非进一步控制循环。总之,原代码的打印不同步是并发执行的正常行为。

回到顶部