【问题标题】:Is there a dead lock in the following go code? Not output though下面的go代码有死锁吗?不通过输出
【发布时间】:2014-07-22 03:41:17
【问题描述】:

我正在运行以下go code,但它不会产生输出:

package main

import "fmt"
//import "strconv"
import "time"

func Wait(){
    time.Sleep(2000 * time.Millisecond)
}

func Print(c chan string){
    fmt.Println("Running Print go-routine")
    for{
        fmt.Println("len(c): ", len(c))
        str := <- c
        fmt.Println(str)
    }
}

func main() {
    c := make(chan string, 4)
    c <- "0"
    c <- "1"
    c <- "2"
    c <- "3"
    Wait()
    fmt.Println("Before go Print(c)")
    go Print(c)
    fmt.Println("After go Print(c)")
}

有死锁吗? Print(c) 函数甚至没有被调用...?这对我来说很奇怪。 Go Playground 中的链接是:http://play.golang.org/p/tDjEJKwkRJ

【问题讨论】:

  • 总是使用go run -race 来测试那种代码。
  • 您的程序在 Print 有机会打印任何内容之前退出。

标签: concurrency go


【解决方案1】:

没有错误,在 goroutine 中调用了 Print() 函数,但随后主程序正在退出......所以 goroutine 被终止。

阅读这篇演讲:Go Concurrency Patterns(或者更好的是 view it's video),了解通道和 goroutine 的工作原理。

请记住,当 main 函数返回时,程序就结束了。

【讨论】:

    【解决方案2】:

    main 函数调用返回时,程序退出。它不会等待其他(非main)goroutine 完成。

    稍后在go Print(c) 语句之后调用您的Wait 函数。例如,

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func Wait() {
        time.Sleep(2000 * time.Millisecond)
    }
    
    func Print(c chan string) {
        fmt.Println("Running Print go-routine")
        for {
            fmt.Println("len(c): ", len(c))
            str := <-c
            fmt.Println(str)
        }
    }
    
    func main() {
        c := make(chan string, 4)
        c <- "0"
        c <- "1"
        c <- "2"
        c <- "3"
        fmt.Println("Before go Print(c)")
        go Print(c)
        Wait()
        fmt.Println("After go Print(c)")
    }
    

    输出:

    Before go Print(c)
    Running Print go-routine
    len(c):  4
    0
    len(c):  3
    1
    len(c):  2
    2
    len(c):  1
    3
    len(c):  0
    After go Print(c)
    

    The Go Programming Language Specification

    Program execution

    通过链接单个未导入的包来创建完整的程序 用它导入的所有包调用主包, 及物的。主包必须有包名 main 并声明 一个不带参数且不返回值的函数 main。

    func main() { … }
    

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

    【讨论】:

    • 请记住,如果这是一个真正的程序,Print 将永远等待,因为您永远不会关闭通道或发出信号停止尝试读取。
    • @OneOfOne: Print 不会永远等待。当main 终止时,它将被杀死。
    • 我知道,我说“如果这是一个真正的程序”。
    • @OneOfOne:“真正的程序”是什么意思?
    • 一个运行 go Print() 并且不会立即退出的程序,例如每次启动它的 http 处理程序,这将是内存泄漏,因为它永远不会退出。
    猜你喜欢
    • 2017-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-02
    • 1970-01-01
    • 2017-07-09
    • 1970-01-01
    • 2021-12-25
    相关资源
    最近更新 更多