为了账号安全,请及时绑定邮箱和手机立即绑定

goroutine 总是执行“后进先出”

goroutine 总是执行“后进先出”

Go
翻阅古今 2021-12-07 17:19:10
为了学习更多关于 Go 的知识,我一直在玩 goroutines,并且注意到了一些东西 - 但我不确定我看到了什么,希望有人能够解释以下行为。以下代码完全符合您的期望:package mainimport (  "fmt")type Test struct {  me int}type Tests []Testfunc (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 mainimport (    "fmt"    "sync")type Test struct {    me int}type Tests []Testfunc (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 可以在与它们产生的顺序不同,但是,我的问题是为什么这总是这样运行。好像有什么很明显的东西我错过了......
查看完整描述

2 回答

?
忽然笑

TA贡献1806条经验 获得超5个赞

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


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 Playground 在设计上是确定性的,这使得缓存程序更容易。


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


查看完整回答
反对 回复 2021-12-07
?
潇潇雨雨

TA贡献1833条经验 获得超4个赞

从 Go 1.5 开始,Go 例程是随机安排的。所以,即使顺序看起来一致,也不要依赖它

请参阅Go 1.5 发行说明:

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

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


查看完整回答
反对 回复 2021-12-07
  • 2 回答
  • 0 关注
  • 207 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信