猿问

去缓冲通道(容量4)接受5而不阻塞

我有 go 代码,它基本上同时运行两个 go 例程。其中一个从 (1-10) 发送 10 个 int 数字到缓冲通道“ch”(容量为 4),另一个 go 例程在for range loop


  package main


  import (

      "fmt"

      "sync"

      "time"

      "runtime"

  )


  func doSm(ch chan int, wg *sync.WaitGroup) {

      defer wg.Done()


      for i := 1; i <= 10; i++ {

          fmt.Println("sending", i)

          ch <- i

          fmt.Println("sent", i)

      }


      close(ch)

  }


  func doSm2(ch chan int, wg *sync.WaitGroup) {

      defer wg.Done()


      time.Sleep(5 * time.Second)

      for v := range ch {

          fmt.Println("result:", v)

      }

  }


  func main() {

      runtime.GOMAXPROCS(1)

      var wg sync.WaitGroup

      ch := make(chan int, 4)


      wg.Add(2)

      go doSm(ch, &wg)

      go doSm2(ch, &wg)

      wg.Wait()

  }

该问题可以在下面的输出中找到。


doSm() 通过 channel 发送 4 个 int 并且 go 调度程序阻塞 go 例程,直到 doSm2() 从 channel 读取这 4 个值。之后,缓冲区为空,doSm() 发送 1 个 int,doSm2() 立即读取它。现在,缓冲区再次为空,准备发送 4 个值。然而,doSm() 以某种方式发送了 5 个值(6、7、8、9、10),尽管它有容量。


sending 1

sent 1

sending 2

sent 2

sending 3

sent 3

sending 4

sent 4

sending 5

result: 1

result: 2

result: 3

result: 4

result: 5

sent 5

sending 6

sent 6

sending 7

sent 7

sending 8

sent 8

sending 9

sent 9

sending 10

sent 10

result: 6

result: 7

result: 8

result: 9

result: 10

知道为什么会这样吗?还是我错过了什么?


Smart猫小萌
浏览 136回答 2
2回答

慕桂英546537

举例说明。result: 5sent 5sending 6sent 6sending 7sent 7sending 8sent 8sending 9sent 9sending 10sent 10result: 6result 5被打印,然后我们看到sent 6-7-8-9-10,然后我们看到result 6打印。这并不意味着这些值6-7-8-9-10都在通道的缓冲区中(显然它们不是)。该值6已从通道接收,但后续fmt.Println()行尚未执行。但由于6接收到,缓冲区中只有 3 个数字,因此10可以在通道上发送,如输出所示。

烙印99

这是一个可能导致此输出的执行:发送 goroutine 发送 4 个值,并打印发送 goroutine 块接收 goroutine 接收一个值发送 goroutine 发送另一个值并打印接收 goroutine 打印接收 goroutine 接收剩余的值通过这种交错,看起来好像发送 goroutine 发送了 5 个值。简而言之:当涉及多个 goroutines 时,打印到 stdout 可能不会显示 goroutines 的实际交错。
随时随地看视频慕课网APP

相关分类

Go
我要回答