goroutines始终执行"最后一次输出"

时间:2016-02-02 12:03:45

标签: go

为了更多地了解Go,我一直在玩goroutines,并注意到了一些东西 - 但我不确定我到底看到了什么,并希望有人能够解释以下行为

以下代码完全符合您的期望:

package main

import (
  "fmt"
)

type Test struct {
  me int
}

type Tests []Test

func (test *Test) show() {
  fmt.Println(test.me)

}

func main() {
  var tests Tests
  for i := 0; i < 10; i++ {
    test := Test{
      me: i,
    }
    tests = append(tests, test)
  }

  for _, test := range tests {
    test.show()
  }

}

按顺序打印0 - 9。

现在,当代码如下所示进行更改时,它始终会返回最后一个代码 - 与我使用的数字无关:

package main

import (
    "fmt"
    "sync"
)

type Test struct {
    me int
}

type Tests []Test

func (test *Test) show(wg *sync.WaitGroup) {
    fmt.Println(test.me)
    wg.Done()

}

func main() {
    var tests Tests
    for i := 0; i < 10; i++ {
        test := Test{
            me: i,
        }
        tests = append(tests, test)
    }

    var wg sync.WaitGroup
    wg.Add(10)
    for _, test := range tests {
        go func(t Test) {
            t.show(&wg)
        }(test)
    }
    wg.Wait()

}

这将返回: 9 0 1 2 3 4 五 6 7 8

循环的迭代顺序没有变化,所以我猜这与goroutines有关... 基本上,我试图理解为什么它的行为是这样的...我理解goroutines可以以与它们产生的顺序不同的顺序运行,但是,我的问题是为什么它总是这样运行。好像有一些非常明显的东西我错过了......

2 个答案:

答案 0 :(得分:3)

正如预期的那样,输出是伪随机的,

package main

import (
    "fmt"
    "runtime"
    "sync"
)

type Test struct {
    me int
}

type Tests []Test

func (test *Test) show(wg *sync.WaitGroup) {
    fmt.Println(test.me)
    wg.Done()

}

func main() {
    fmt.Println("GOMAXPROCS", runtime.GOMAXPROCS(0))
    var tests Tests
    for i := 0; i < 10; i++ {
        test := Test{
            me: i,
        }
        tests = append(tests, test)
    }

    var wg sync.WaitGroup
    wg.Add(10)
    for _, test := range tests {
        go func(t Test) {
            t.show(&wg)
        }(test)
    }
    wg.Wait()

}

输出:

$ go version
go version devel +af15bee Fri Jan 29 18:29:10 2016 +0000 linux/amd64
$ go run goroutine.go
GOMAXPROCS 4
9
4
5
6
7
8
1
2
3
0
$ go run goroutine.go
GOMAXPROCS 4
9
3
0
1
2
7
4
8
5
6
$ go run goroutine.go
GOMAXPROCS 4
1
9
6
8
4
3
0
5
7
2
$ 

你在Go游乐场跑步吗?根据设计,Go游乐场是确定性的,这使得缓存程序变得更容易。

或者,您是否正在运行runtime.GOMAXPROCS = 1?这按顺序一次运行一件事。这就是Go游乐场所做的。

答案 1 :(得分:3)

自Go 1.5以来,Go例程是随机安排的。因此,即使订单看起来一致,也不要依赖它

请参阅Go 1.5 release注意:

  

在Go 1.5中,计划了goroutine的顺序已更改。调度程序的属性从未由语言定义,但依赖于调度顺序的程序可能会被此更改破坏。我们已经看到一些(错误的)程序受到这种变化的影响。如果您的程序隐式依赖于计划顺序,则需要更新它们。

     

另一个可能发生重大变化的是,运行时现在将由GOMAXPROCS定义的同时运行的默认线程数设置为CPU上可用的核心数。在以前的版本中,默认值为1.不希望运行多个内核的程序可能会无意中断。可以通过删除限制或通过显式设置GOMAXPROCS来更新它们。有关此更改的更详细讨论,请参阅设计文档。