【问题标题】:Length of channel is zero after adding element添加元素后通道长度为零
【发布时间】:2020-01-18 09:33:54
【问题描述】:

我在 Go 中学习缓冲通道,但对我隐藏了一些魔法。 我有这个代码

package main

import (
    "fmt"
)

func write(ch chan int) {
    for i := 1; i <= 5; i++ {
        ch <- i
        fmt.Printf("Channel's length is %d\n", len(ch))
    }
    close(ch)
}
func main() {
    ch := make(chan int, 2)
    go write(ch)

    for v := range ch {
        fmt.Println(v)
    }
}

输出是

Channel's length is 0
Channel's length is 1
Channel's length is 2
1
2
3
4
Channel's length is 2
Channel's length is 0
5

为什么 write goroutine 的第一次迭代时通道的长度为零?我不知道什么?

【问题讨论】:

  • 你有 2 个并发的 goroutine,一个(main)正在从通道接收值,所以无论你在那个通道中“放入”什么,它都可能立即被删除。在您的频道上发送和获得它的长度之间有一些“时间”。在此期间,不能保证不会触摸通道。
  • 在缓冲通道已满之前,写入 goroutine 是否应该处于活动状态?
  • 没有。它们同时运行。从概念上讲,您应该假设它们同时处于活动状态 - 这就是“并发”的定义。

标签: go channel goland


【解决方案1】:

根据 GO 缓冲区的概念,您可以根据定义的缓冲区大小(在您的情况下为 2)将元素推送到通道中。但是当一个元素被推入通道时,主 GO 例程正在读取相同的元素,这导致通道的大小减小到零。因此,如果您在 read 语句之前放置一些 time.Sleep,您将获得预期的结果。

`

package main
import (
    "fmt"
    "time"
)

func write(ch chan int) {
    for i := 1; i <= 5; i++ {
        ch <- i
        fmt.Printf("Channel's length is %d\n", len(ch))
    }
    close(ch)
}
func main() {
    ch := make(chan int, 2)
    go write(ch)
    time.Sleep(2*time.Second)
    for v := range ch {
        fmt.Println(v)
        time.Sleep(2*time.Second)
    }
}`
上述代码的

输出为:

频道的长度为 1

频道的长度是2

1

频道的长度是2

2

频道的长度是2

3

频道的长度是2

4

5

【讨论】:

    猜你喜欢
    • 2019-06-05
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 2016-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多