【问题标题】:go lang, why go routine function never being calledgolang,为什么永远不会调用 goroutine 函数
【发布时间】:2015-04-15 15:26:36
【问题描述】:
package main

import (
    "fmt"
    //"runtime"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        //runtime.Gosched()
        fmt.Println(s)
    }
}

func main() {
    go say("world") // create a new goroutine
    say("hello") // current goroutine
}

为什么结果是:

你好
你好
你好
你好
你好

为什么没有world

答案:(已编辑:) 如果我这样做,现在很好:

package main

import (
    "fmt"
    "runtime"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        //runtime.Gosched()
        fmt.Println(s)
    }
}

func main() {
    go say("world") // create a new goroutine
    runtime.Gosched()

    say("hello") // current goroutine
}

【问题讨论】:

标签: go


【解决方案1】:

您只是遇到了时间问题,因为您没有“协调”您的围棋程序。处理这种情况的常用方法是使用等待守卫。我不时看到的另一个选项是使用通道和阻塞选择。等待守卫的实现看起来像这样;

func main() {
    wg := sync.WaitGroup{}
    wg.Add(1)
    go say("world") // create a new goroutine

    wg.Add(1)
    say("hello") // current goroutine
    wg.Wait()
}

虽然频道选项(在此示例中实际上并不有趣或有用)更像这样;

 func main() {
    done := make(chan bool)
    go say("world", done) // create a new goroutine

    say("hello", done) // current goroutine

    select {
        case fin := <- done:
           //on finished
           return
    }
}

func say(s string, chan bool) {
for i := 0; i < 5; i++ {
    fmt.Println(s)
   }
   done <- true
}

不过,对于上面的示例,第一次调用完成将允许程序完成执行。为确保两者都完成,您必须将不同的通道传递给每个通道并在两个通道上都进行阻塞读取。当您的 goroutine 进行实际工作并且您希望将数据从它们中聚合数据或需要更复杂的协调(例如根据之前的结果生成新的 goroutine 等)时,我会使用这种模式。

【讨论】:

    【解决方案2】:

    您不允许 goroutine 在 main() 退出之前运行。

    即使对say 的第二次调用阻塞(简要地),也不能保证第一个goroutine 可以运行。您需要等待两者都返回,这通常通过 WaitGroup 完成

    var wg sync.WaitGroup
    
    func say(s string) {
        defer wg.Done()
        for i := 0; i < 5; i++ {
            //runtime.Gosched()
            fmt.Println(s)
        }
    }
    
    func main() {
        wg.Add(1)
        go say("world") // create a new goroutine
    
        wg.Add(1)
        say("hello") // current goroutine
        wg.Wait()
    }
    

    【讨论】:

      【解决方案3】:

      这是因为主 goroutine 过早退出。当主协程退出时,进程将退出,因此其他协程没有机会运行。如果您希望 goroutine 运行,请让主例程保持足够长的时间。

      package main
      
      import (
          "fmt"
          "runtime"
      )
      
      func say(s string) {
          for i := 0; i < 5; i++ {
              fmt.Println(s)
          }
      }
      
      func main() {
          go say("world") // create a new goroutine
          runtime.Gosched()
      
          say("hello") // current goroutine
          time.Sleep(1 * time.Second) // this line
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-22
        相关资源
        最近更新 更多