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返回数据。由于调度是“随机”的,他们在执行时是不能保证顺序的,程序中也不应该依赖他们的执行顺序。

0

首先你创建的是无缓冲的channel.就是同步操作了。在main中通过go开启一个协程A。他是要从data中获取数据的。channel data中是空的,阻塞(等待数据放入)。这时候main协程继续执行。将1放入data.此时同理。data又一次阻塞。必须等待其他协程将1取出才能执行下面的操作。这时候data又是可以放入数据的状态。2是放进去了。但是此时main协程中没有再向data中放入数据的操作。所以main协程并不会阻塞。可以继续执行。即可以进行close操作以及println操作。此时由于协程调度原因,并不能确定是main先执行下面的操作还是协程A执行从data中获取数据的操作。所以输出2,send over,receive over的顺序是无法确认的(当然从代码的角度输出receive over肯定是在close之后的)。不过main协程中最后从exit中获取数据肯定是等待协程A将true放入exit中之后才执行的。如果在<-exit后面println("over")操作,可以确定over是最后输出的

撰写答案

SegmentFault

一起探索更多未知

下载 App