0

1.通过go run example.go执行,执行输出顺序为啥不是

1
2
send over
receive over

2.贴代码

package main

func main() {
    data := make(chan int)
    exit := make(chan bool)

    go func() {
        for v := range data {
            println(v)
        }

        println("receive over")
        exit <- true
    }()

    data <- 1
    data <- 2
    // data <- 3
    close(data)

    println("send over")
    <-exit
}

3.环境说明:

Go Version:go1.4.2 darwin/amd64
MacBook Pro (Retina, 13-inch, Early 2015)
2.7 GHz Intel Core i5
8 GB 1867 MHz DDR3

查看全部 2 个回答

2

你的执行顺序应该是:

1
send over
2
receive over

由于 channel是的发送和读取都是阻塞操作。

  1. 写入1之后,再写入2被阻塞,cpu让出执行go出的协程,打印出1

  2. 再次进入for循环读取channel被阻塞,cpu让出,回到主协程写入2成功,close成功,print成功,输出 send over

  3. 读取channel exit被阻塞,cpu让出,执行go出协程,打印出2

  4. 由于channel 被关闭,for结束,打印出 receive over,写入 exit,阻塞,cpu让出

  5. 读取到 exit的值,程序终止


如果你使用 Go1.5以上版本,多执行几次,你会发现顺序都不是固定的:

➜  tt go run main.go
1
send over
2
receive over
➜  tt go run main.go
1
2
send over
receive over
➜  tt go run main.go
1
2
send over
receive over
➜  tt go run main.go
1
2
send over
receive over
➜  tt go run main.go
1
2
send over
receive over
➜  tt go run main.go
1
send over
2
receive over

Go从1.5版本开始,默认采用多核执行,默认是你的CPU核心数,以前版本默认为1.

By default, Go programs run with GOMAXPROCS set to the number of cores available; in prior releases it defaulted to 1.

https://golang.org/doc/go1.5#...

go开启了一个协程,main其实也是一个协程,我们称之为主协程,主协程和go出去的协程都是协程,并没有绝对的执行顺序,他们是并行调度的,在 close(data)之后,可能go出去的协程先执行完了,也可能主协程print完了坐等exit channel返回数据。由于调度是“随机”的,他们在执行时是不能保证顺序的,程序中也不应该依赖他们的执行顺序。