【问题标题】:Why the last goroutine starts first in a loop with two goroutines?为什么最后一个 goroutine 首先在两个 goroutine 的循环中开始?
【发布时间】:2021-09-14 21:38:07
【问题描述】:

我一直在用 goroutine 做一些测试,我注意到使用这段代码的一个奇怪的行为(对我来说):

游乐场:https://play.golang.org/p/Py4oqGqkYKm

package main

import (
    "fmt"
    "sync"
)
var (
    mu sync.Mutex
    wg sync.WaitGroup
)

func main() {
    var x int
    for i := 0; i < 10; i++ {
        wg.Add(2)
        go func() {
            mu.Lock()
            x = i
            mu.Unlock()
            wg.Done()
        }()
        go func() {
            mu.Lock()
            fmt.Print("x: ", x, " \n")
            mu.Unlock()
            wg.Done()
        }()
        wg.Wait()
    }
}

我期望输出如下内容:

x: 0 
x: 1 
x: 2 
x: 3 
x: 4 
x: 5 
x: 6 
x: 7 
x: 8 
x: 9 

但我收到了:

x: 0 
x: 0 
x: 1 
x: 2 
x: 3 
x: 4 
x: 5 
x: 6 
x: 7 
x: 8 

看起来第二个 goroutines 是首先被调用的(比如 LIFO)。考虑到这一点,我尝试反转 goroutines,并收到了我所期望的答案:

游乐场:https://play.golang.org/p/BC1r3NK6RBm

package main

import (
    "fmt"
    "sync"
)

var (
    mu sync.Mutex
    wg sync.WaitGroup
)

func main() {
    var x int
    for i := 0; i < 10; i++ {
        wg.Add(2)
        go func() {
            mu.Lock()
            fmt.Print("x: ", x, " \n")
            mu.Unlock()
            wg.Done()
        }()
        go func() {
            mu.Lock()
            x = i
            mu.Unlock()
            wg.Done()
        }()
        wg.Wait()
    }
}

输出:

x: 0 
x: 1 
x: 2 
x: 3 
x: 4 
x: 5 
x: 6 
x: 7 
x: 8 
x: 9 

谁能帮我理解这种行为?

Go 版本: go version go1.16.2 linux/amd64

【问题讨论】:

  • @PenelopeStevens 这个评论有助于更好地理解......我们无法控制首先调用哪个互斥锁,对吧?所以,参加我想做的事情,我需要使用这样的频道:play.golang.org/p/OVK4hTQSu_d 对吗?
  • “并发进程”的全部意义在于它们的相对顺序没有定义。

标签: go mutex goroutine


【解决方案1】:

Go 语言没有指定 goroutine 在使用通道、互斥锁、等待组等的显式同步之外执行的顺序。该规范允许两个程序的两种输出。

您正在观察获取互斥锁的顺序,而不是 goroutine 启动的顺序。可能是 goroutine 以您预期的顺序启动,但意外的 goroutine 首先调用了 Lock()。

程序确保的唯一顺序是通过等待组:每对 goroutine 将在下一对启动之前完成。

【讨论】:

    【解决方案2】:

    Go 例程提供并发性并在具有独立堆栈内存的共享堆分配之上工作。它们的目的是在多核系统之上提供并发执行。没有关于它们如何并行执行的控制因素。这是由实际的处理器决定的。我们只通过抽象层使用处理器。

    实际上没有可以控制/预测结果的并发系统。

    【讨论】:

    • "这由实际的处理器决定。" --- Go 运行时不决定吗?
    猜你喜欢
    • 2021-12-27
    • 1970-01-01
    • 2017-07-14
    • 2015-06-28
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    • 2014-11-03
    • 2021-11-30
    相关资源
    最近更新 更多