【问题标题】:Strange Goroutines Behaviour奇怪的 Goroutines 行为
【发布时间】:2013-07-29 16:30:11
【问题描述】:

如果我错了,请纠正我。据我所知,goroutine 的工作方式与线程大致相似。因此,如果我使用 go 前缀生成具有不同参数的相同函数。它应该工作得很好?

package main

import "fmt"


func f(from string) {
    for i := 0; i < 3; i++ {
        fmt.Println(from, ":", i)
    }
}

func main() {
    go f("direct")
    go f("redirect")
    //var input string
    //fmt.Scanln(&input)

}

实际输出:

rahul@g3ck0:~/programs/go$ go run goroutine.go 
rahul@g3ck0:~/programs/go$ 

我只是得到提示。

预期输出:

direct : 0
direct : 1
direct : 2
redirect : 0
redirect : 1
redirect : 2

不一定是相同的顺序。
无法理解这种奇怪的行为。我错过了什么吗?

编辑:添加 Scan 语句可以解决它。但是有没有更好的方法呢?

【问题讨论】:

    标签: go goroutine


    【解决方案1】:

    当 main 退出时,无论其他 goroutine 的状态如何,程序都会终止。您可以通过在 main 函数的末尾添加 select{} 来测试它。这将导致 main 永远不会退出,您将看到其他 goroutines 运行。

    如果你希望你的程序在两个 goroutine 都完成时干净地退出(没有死锁),你需要使用通道或 sync.Waitgroup 之类的东西来在一切都完成时协调主结束。

    使用 sync.Waitgroup 的示例:

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    func f(from string, wg *sync.WaitGroup) {
        for i := 0; i < 3; i++ {
            fmt.Println(from, ":", i)
        }
    
        wg.Done()
    }
    
    func main() {
        wg := new(sync.WaitGroup)
        wg.Add(2)
    
        go f("direct", wg)
        go f("redirect", wg)
    
        wg.Wait()
    }
    

    使用渠道的示例:

    package main
    
    import (
        "fmt"
    )
    
    func f(from string, ch chan<- bool) {
        for i := 0; i < 3; i++ {
            fmt.Println(from, ":", i)
        }
    
        ch <- true
    }
    
    func main() {
        ch := make(chan bool)
    
        go f("direct", ch)
        go f("redirect", ch)
    
        <-ch
        <-ch
    }
    

    【讨论】:

    • 添加 select{} 似乎是一种 hack。我得到以下提示:所有 goroutine 都在睡觉 - 死锁! goroutine 1 [select (no case)]: main.main() /home/rahul/programs/go/goroutine.go:15 +0x53 goroutine 2 [syscall]: 由 runtime.main 创建 /build/buildd/golang-1 /src/pkg/runtime/proc.c:221 退出状态2
    • 是的,select{} 是一个黑客。但就是显示问题。正如我在回答中所说,使用并发类型(例如通道或同步包中的其他内容)是处理此问题的正确方法。
    • 现在一切都说得通了。谢谢斯蒂芬!
    【解决方案2】:

    如上所述,最后的 select{} 确保显示输出,但您不能期望 go 例程以特殊顺序运行。

    如果您并行运行 go 例程,则永远无法保证它们将以什么顺序运行。你不能让它们按顺序运行,因为它们是并行运行的!

    您可能会在一台机器上一次又一次地获得预期的输出,但不能保证每次在任何给定机器上都按顺序打印输出!!

    【讨论】:

      猜你喜欢
      • 2021-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 2015-07-20
      • 2010-10-03
      • 2021-07-12
      相关资源
      最近更新 更多