1
package main 
import (
    "fmt"
    "time"
)

var message chan string

func main() {
    message = make(chan string)
    count := 6
    flag := "first"
    go func() {
        fmt.Println("child go ",flag)
        for i := 0; i < count; i++ {
            fmt.Println("set:",i)
            message <- fmt.Sprintf("message %d",i)
        }   
    }()

    time.Sleep(time.Second * 0)

    fmt.Println("main thread ",flag)
    flag = "last"
    for i := 0 ; i < count; i++ {
        fmt.Println("get:",i)
        fmt.Println(<-message)
    }
}

我运行代码,结果是:

main thread  first
get: 0
child go  last
set: 0
set: 1
message 0
get: 1
message 1
get: 2
set: 2
set: 3
message 2
get: 3
message 3
get: 4
set: 4
set: 5
message 4
get: 5
message 5

我对结果感到困惑。为什么在“get 1”之后出现“message 1”而不是“set 2”?这让我困惑了好几天!

我认为当它“获取 1”时,应该阻止主 go 例程并且应该执行子 go 例程,将“消息 1”发送到通道消息并继续 for 循环并打印“设置 2”,因此被阻止将“消息 2”发送到通道,因此主 go 例程开始运行,输出“消息 1”。

4

1 回答 1

1

该代码完全按照您的想法执行(如果我理解您认为它应该执行的操作):从message块接收直到发送值。不幸的是,您的代码在通道上发送之前会打印“set 2”,并且此操作不会被阻止。

同步只发生在<-, 通道发送之前的 Println 可以运行。看看http://play.golang.org/p/d6_SkBugqs,它在每次发送/接收操作之前和之后打印,你会发现一切都被正确地同步化了:所有“post-recv n”都发生在“pre-发送 n"。

于 2014-07-28T09:54:30.790 回答