理解 Goroutine 执行顺序
在基于 goroutine 的程序中,goroutine 的执行顺序可能是不可预测的。这是因为 goroutine 是并发执行的,并且无法保证它们何时或以什么顺序完成任务。
考虑以下代码片段:
func sum(a []int, c chan int) { fmt.Println("summing: ", a) total := 0 for _, v := range a { total += v } c <- total // send total to c } func main() { c := make(chan int) go sum([]int{1,2,3}, c) go sum([]int{4,5,6}, c) x := <-c fmt.Println(x) x = <-c fmt.Println(x) }
在此示例中,有两个 goroutine启动来计算两个整数切片的总和。但是,它们的执行顺序和打印结果的顺序并不确定。您可以将输出观察为:
summing: [4 5 6] 15 summing: [1 2 3] 6
或
summing: [1 2 3] 6 summing: [4 5 6] 15
要同步 Goroutines 的执行顺序,可以采用多种方法:
使用阻塞通道:
通过使用通道的阻塞性质,您可以强制main goroutine 等待每个 goroutine 完成,然后再继续下一个。例如:
func main() { c := make(chan int) go sum([]int{1, 2, 3}, c) // Blocks until a value is received x := <-c fmt.Println(x) // Execute the next goroutine go sum([]int{4, 5, 6}, c) x = <-c fmt.Println(x) }
使用等待组:
另一种常见的同步技术涉及使用等待组。等待组跟踪仍在运行的 goroutine 数量,并等待它们全部完成,然后再继续下一步。以下是在上面的示例中使用等待组的方法:
func sum(a []int, c chan int, wg *sync.WaitGroup) { defer wg.Done() fmt.Println("summing: ", a) total := 0 for _, v := range a { total += v } c <- total // send total to c } func main() { c := make(chan int) wg := new(sync.WaitGroup) // Increment the wait group wg.Add(1) // Launch the first goroutine go sum([]int{1, 2, 3}, c, wg) // Wait for the first goroutine to complete wg.Wait() // Increment the wait group again wg.Add(1) // Launch the second goroutine go sum([]int{4, 5, 6}, c, wg) // Wait for the second goroutine to complete wg.Wait() // Close the channel to indicate that no more values will be sent close(c) // Range over the channel to receive the results for theSum := range c { x := theSum fmt.Println(x) } }
通过将同步技术合并到代码中,您可以更好地控制 goroutine 的执行顺序,确保它们在所需的顺序。
以上是Go中如何控制Goroutines的执行顺序?的详细内容。更多信息请关注PHP中文网其他相关文章!