【问题标题】:Goroutine does not execute if time.Sleep included如果包含 time.Sleep,Goroutine 不会执行
【发布时间】:2015-04-03 04:08:21
【问题描述】:

以下代码运行良好:

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 完成执行之前返回,但似乎添加暂停应该没有任何效果。我完全迷失在这个简单的例子中,这是怎么回事?

【问题讨论】:

    标签: go concurrency channel goroutine


    【解决方案1】:

    main 函数结束时,程序也随之结束。它不会等待其他 goroutine 完成。

    引用Go Language Specification: Program Execution:

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

    因此,当您的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将接收来自main()的通道c的值。但是一旦接收到值,main 函数可能 会继续,但由于发送后没有更多的语句,它只是与程序一起结束。非main 协程是否有时间机会 使用fmt.Println() 打印它未定义

    【讨论】:

    • 你能解释一下为什么在我的第一个示例中my_func 在主要结束之前完成,但在第二个示例中没有?
    • 我认为这是正确的答案,但如果添加一些信息可能会更好:一种(或多种)让示例代码等待的方法......
    • 添加说明和示例如何确保在通道上发送的值被打印。
    • 我想我明白了,但我想确定一下。我的理解是否正确:“第一个和第二个示例,我的 goroutine 可能会或可能无法在 main 完成之前完成,而它发生在第一个示例而不是第二个示例中的事实只是纯粹的机会。
    • @Akavall 是的,在这两种情况下,值可能会或可能不会被打印出来。请注意,在 Go Playground 上,程序的结果会被缓存。因此,如果在某种情况下它被打印出来,运行相同的程序总是会打印它(直到有人删除了程序的输出缓存)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-09
    • 2013-03-24
    • 1970-01-01
    • 2014-09-23
    • 2022-11-10
    • 2013-05-04
    • 1970-01-01
    相关资源
    最近更新 更多