猿问

goroutine 总是执行“后进先出”

为了学习更多关于 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 5 6 7 8


循环的迭代顺序没有改变,所以我想这与 goroutines 有关系……基本上,我试图理解为什么它的行为是这样的……我知道 goroutines 可以在与它们产生的顺序不同,但是,我的问题是为什么这总是这样运行。好像有什么很明显的东西我错过了......


翻阅古今
浏览 208回答 2
2回答

忽然笑

正如预期的那样,输出是伪随机的,package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "runtime"&nbsp; &nbsp; "sync")type Test struct {&nbsp; &nbsp; me int}type Tests []Testfunc (test *Test) show(wg *sync.WaitGroup) {&nbsp; &nbsp; fmt.Println(test.me)&nbsp; &nbsp; wg.Done()}func main() {&nbsp; &nbsp; fmt.Println("GOMAXPROCS", runtime.GOMAXPROCS(0))&nbsp; &nbsp; var tests Tests&nbsp; &nbsp; for i := 0; i < 10; i++ {&nbsp; &nbsp; &nbsp; &nbsp; test := Test{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; me: i,&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; tests = append(tests, test)&nbsp; &nbsp; }&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; wg.Add(10)&nbsp; &nbsp; for _, test := range tests {&nbsp; &nbsp; &nbsp; &nbsp; go func(t Test) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.show(&wg)&nbsp; &nbsp; &nbsp; &nbsp; }(test)&nbsp; &nbsp; }&nbsp; &nbsp; wg.Wait()}输出:$ go versiongo version devel +af15bee Fri Jan 29 18:29:10 2016 +0000 linux/amd64$ go run goroutine.goGOMAXPROCS 49456781230$ go run goroutine.goGOMAXPROCS 49301274856$ go run goroutine.goGOMAXPROCS 41968430572$&nbsp;你在围棋操场上跑步吗?Go Playground 在设计上是确定性的,这使得缓存程序更容易。或者,您是否使用 runtime.GOMAXPROCS = 1 运行?这一次按顺序运行一件事。这就是 Go 游乐场所做的。

潇潇雨雨

从 Go 1.5 开始,Go 例程是随机安排的。所以,即使顺序看起来一致,也不要依赖它。请参阅Go 1.5 发行说明:在 Go 1.5 中,goroutine 的调度顺序已经改变。调度程序的属性从未由语言定义,但依赖于调度顺序的程序可能会被这种更改破坏。我们已经看到一些(错误的)程序受到此更改的影响。如果您有隐式依赖调度顺序的程序,则需要更新它们。另一个潜在的重大变化是,运行时现在将同时运行的默认线程数(由 GOMAXPROCS 定义)设置为 CPU 上可用的内核数。在以前的版本中,默认值为 1。不希望以多核运行的程序可能会无意中中断。可以通过删除限制或明确设置 GOMAXPROCS 来更新它们。有关此更改的更详细讨论,请参阅设计文档。
随时随地看视频慕课网APP

相关分类

Go
我要回答