如果time.Sleep包含,Goroutine不会执行

时间:2015-02-03 20:07:23

标签: go concurrency channel goroutine

以下代码运行完全正常:

package main

import (
    "fmt"
)

func my_func(c chan int){
    fmt.Println(<-c)
}

func main(){
    c := make(chan int)
    go my_func(c)

    c<-3
}

playgound_1

但是,如果我改变

c<-3

time.Sleep(time.Second)
c<-3

playground_2

我的代码没有执行。

我的直觉是,mainmy_func完成执行之前会以某种方式{{1}}返回,但似乎添加暂停应该没有任何效果。我完全迷失在这个简单的例子上,这里发生了什么?

1 个答案:

答案 0 :(得分:12)

main函数结束时,程序以此结束。它不会等待其他goroutines完成。

引用Go Language Specification: Program Execution

  

程序执行从初始化主包然后调用函数main开始。当该函数调用返回时,程序退出。它不会等待其他(非main)goroutines完成。

因此,当您的main函数通过在通道上发送值成功时,程序可能会立即终止,然后另一个goroutine有机会将接收到的值打印到控制台。

如果要确保将值打印到控制台,则必须将其与退出main函数的事件同步:

“完成”频道的示例(在Go Playground上尝试):

func my_func(c, done chan int) {
    fmt.Println(<-c)
    done <- 1
}

func main() {
    c := make(chan int)
    done := make(chan int)
    go my_func(c, done)

    time.Sleep(time.Second)
    c <- 3
    <-done
}

由于done也是一个无缓冲的通道,因此在main函数末尾从它接收必须等待done通道上的值发送,这在值之后发生已收到已在频道c上发送的内容并将其打印到控制台。

对看似不确定的运行的解释:

Goroutines可能会或可能不会同时并行执行 。同步可确保某些事件在其他事件发生之前发生。这是您获得的唯一保证,也是您应该依赖的唯一保证。 此之前发生的2个示例

  
      
  • 启动新goroutine的go语句在goroutine执行开始之前发生。
  •   
  • 频道上的发送在该频道的相应接收完成之前发生。
  •   

有关详细信息,请参阅The Go Memory Model

回到您的示例:

  

来自无缓冲通道的接收在该通道上的发送完成之前发生。

因此,您获得的唯一保证是运行my_func()的goroutine将从c发送的频道main()中获得值。但是一旦收到值,main函数可能继续,但由于发送后没有更多的语句,它只是结束 - 与程序一起。非main goroutine是否时间偶然使用fmt.Println()打印未定义。< / p>