Go 循环中的互斥导致意外输出

Go 循环中的互斥导致意外输出,go,concurrency,Go,Concurrency,我有一段过于简单的代码(或在这里) 从输出来看,我对以下几点感到惊讶: 对于j 对于j 对于i=1,只有3个值,而不是4个值 我可以理解缺少“1”的原因,因为变量在写入之前是递增的 有人能解释一下吗。和3 在循环中关闭变量,然后在单独的线程中运行闭包,而这些变量会继续更改。当您这样做时,请期待意外的结果-例如,您会看到5s,因为j在上一次迭代中增加到5,这会导致循环结束,但j仍保留5,单独的线程可以读取该值。它与互斥无关;这是变量的跨线程共享。如果您使用: go func(i,j int) {

我有一段过于简单的代码(或在这里)

从输出来看,我对以下几点感到惊讶:

  • 对于
    j
  • 对于
    j
  • 对于i=1,只有3个值,而不是4个值
  • 我可以理解缺少“1”的原因,因为变量在写入之前是递增的


    有人能解释一下吗。和3

    在循环中关闭变量,然后在单独的线程中运行闭包,而这些变量会继续更改。当您这样做时,请期待意外的结果-例如,您会看到5s,因为
    j
    在上一次迭代中增加到5,这会导致循环结束,但
    j
    仍保留5,单独的线程可以读取该值。它与互斥无关;这是变量的跨线程共享。如果您使用:

    go func(i,j int) {
        fmt.Printf("%d + %d = %d\n", i, j, j+i)
        mutex.Unlock()
    }(i,j)
    

    然后它将在goroutine启动时传入
    i
    j
    的值,后续迭代不会影响它:

    执行此操作时:

    go func() {
                    fmt.Printf("%d + %d = %d\n", i, j, j+i)
                    mutex.Unlock()
                }()
    
    当前goroutine生成另一个循环,该循环增加j

    增量发生在printf之前,这就是为什么我们甚至认为函数是在调用时调用的
    j
    <5
    在函数有时间打印值之前,它可以增加到5。
    换句话说,您的程序运行方式如下:

    • 进入循环
    • 锁互斥
    • 调用func()
    • 增量j
    • 打印值
    • 解锁互斥锁

    解决方法是将值按值传递给函数,而不是在整个goroutine中共享它们。

    请注意,您缺少最终的
    4+4
    ,因为您没有等待最后一个goroutine完成。我知道将
    I
    j
    作为函数参数传递在这里会有所帮助。我缺少循环的
    基础,即先递增该变量,然后检查条件。这就解释了5s
    
    go func(i,j int) {
        fmt.Printf("%d + %d = %d\n", i, j, j+i)
        mutex.Unlock()
    }(i,j)
    
    go func() {
                    fmt.Printf("%d + %d = %d\n", i, j, j+i)
                    mutex.Unlock()
                }()