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

标签 go concurrency channel go-scheduler

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

  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
知道为什么会这样吗?还是我错过了什么?

最佳答案

举例说明。

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 5打印出来,然后我们看到sent 6-7-8-9-10 ,然后我们看到 result 6打印。这并不意味着值 6-7-8-9-10都在 channel 的缓冲区中(显然它们不是)。值 6已经从 channel 收到了,但是后面的 fmt.Println()行尚未执行。但是自从6收到,缓冲区中只有 3 个数字,所以 10可以在 channel 上发送,如输出所示。

关于去缓冲 channel (容量4)接受5而不阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63254668/

相关文章:

Go 在循环外声明变量 vs 在循环内声明变量

c++ - 双缓冲系统并发处理的设计?

rust - 如何在没有不稳定功能或外部包装箱的情况下从 mpsc::channel 读取指定的时间?

file - 如何优化从 Go 中的文本文件中查找字谜

go - 将 web api 暴露给使用 Golang 接受 json 和/或参数的第三方

proxy - golang反向代理不工作

ruby - 事件驱动的应用程序 - 选择什么语言或 VM?

sql - Oracle SQL - SELECT 查询锁定索引并阻止 DML session

go - 如何获取无缓冲 channel 中的元素数量

select - Go 中的 channel 阻塞是如何工作的?