【问题标题】:Goroutine execution orderGoroutine 执行顺序
【发布时间】:2018-08-12 16:20:35
【问题描述】:

我是golang的初学者,正在学习goroutine和channel。直觉上,我认为 golang 中的 gorountine 本质上是一个独立运行的线程。因此,如果有多个 goroutine,则无法保证执行顺序。因此,以下代码应以随机顺序输出“ping”和“pong”。但是,我观察到程序会依次产生“ping”和“pong”。谁能解释我的原因?任何回复都会有所帮助。谢谢!

我发现的另一个有趣的观察是,如果我不在打印机函数中调用 sleep 函数,程序将按随机顺序输出。

package main

import (
  "fmt"
  "time"
)

func pinger(c chan string) {
  for i := 0; ; i++ {
    c <- "ping"
  }
}

func printer(c chan string) {
  for {
    msg := <- c
    fmt.Println(msg)
    time.Sleep(time.Second * 1)
  }
}

func ponger(c chan string) {
  for i := 0; ; i++ {
    c <- "pong"
  }
}

func main() {
  var c chan string = make(chan string)

  go pinger(c)
  go ponger(c)
  go printer(c)

  var input string
  fmt.Scanln(&input)
}

【问题讨论】:

    标签: go concurrency goroutine


    【解决方案1】:

    The Go Programming Language Specification

    Channel types

    容量,以元素数量为单位,设置缓冲区的大小 这个频道。如果容量为零或不存在,则通道为 无缓冲和通信成功,只有当发送者和 接收器已准备就绪。


    您有一个无缓冲频道:make(chan string)

    msg := &lt;- c(准备接收)和c &lt;- "ping"(准备发送):发送和接收"ping"

    msg := &lt;- c(准备接收)和c &lt;- "pong"(准备发送):发送和接收"pong"

    【讨论】:

      【解决方案2】:

      为了更好地理解,请考虑以下语句和演示程序:

      1. 将按照尝试发送的顺序处理阻塞通道上的发送。我不是 100% 确定这一点,但演示程序显示了这种行为,而且这个 [ticket][1] 提到在 2 年前实现了这种行为。

      要真正看到这一点,你应该在你的机器上运行它:

      package main
      
      import (
          "fmt"
          "time"
      )
      
      func main() {
          count := 10
          c := make(chan int)
          for i := 0; i < count; i++ {
              go func(i int) {
                  c <- i + 1
              }(i)
          }
          for i := 0; i < count; i++ {
              fmt.Println("c", <-c)
          }
      
          fmt.Println()
      
          d := make(chan int)
          for i := 0; i < count; i++ {
              go func(i int) {
                  d <- i + 1
              }(i)
              time.Sleep(time.Millisecond * 5)
          }
          for i := 0; i < count; i++ {
              fmt.Println("d", <-d)
          }
      
          var input string
          fmt.Scanln(&input)
      }
      

      这里是一个操场,尽管发生的事情不会那么明显,因为第一组 (c) 将始终以一致(尽管未排序)的顺序出现。第二组 (d) 将始终按顺序出现在操场上或本地。

      https://play.golang.org/p/JCVyVlFPRXS

      这些是本地 3 次运行的输出

       1     2     3
      ----------------
      c 2   c 10  c 10
      c 1   c 4   c 2
      c 6   c 1   c 1
      c 3   c 2   c 4
      c 4   c 3   c 3
      c 5   c 7   c 5
      c 8   c 5   c 8
      c 7   c 6   c 7
      c 9   c 8   c 9
      c 10  c 9   c 6
      
      d 1   d 1   d 1
      d 2   d 2   d 2
      d 3   d 3   d 3
      d 4   d 4   d 4
      d 5   d 5   d 5
      d 6   d 6   d 6
      d 7   d 7   d 7
      d 8   d 8   d 8
      d 9   d 9   d 9
      d 10  d 10  d 10
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-16
        • 2016-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-23
        • 2013-11-12
        • 2012-04-10
        相关资源
        最近更新 更多