为什么我会从一个已关闭的通道接收到值?

huangapple go评论74阅读模式
英文:

Why do I receive values from a closed channel?

问题

我正在调查通道的行为,并且对它们的行为感到困惑。规范中说:“在调用close之后,并且在接收到之前发送的所有值之后,接收操作将返回通道类型的零值,而不会阻塞。”然而,即使在那个时候通道已经关闭,我仍然在range语句中获取到值。为什么会这样呢?

package main

import "fmt"
import "sync"
import "time"

func main() {
    iCh := make(chan int, 99)
    var wg sync.WaitGroup
    go func() {
        for i := 0; i < 5; i++ {
            wg.Add(1)
            go func(i int) {
                defer wg.Done()
                iCh <- i
            }(i)

        }
        wg.Wait()
        close(iCh)
    }()
    time.Sleep(5 * time.Second)
    print("通道现在应该已经关闭了\n")
    for i := range iCh {
        fmt.Printf("%v\n", i)
    }
    print("完成")
}

**编辑:**如果我将close语句移到通道的range之前,它会彻底关闭通道。所以我想知道为什么使用"time.Sleep"的技巧不起作用。到那个时候(5秒),所有的goroutine应该已经完成并且通道已经关闭了,不是吗?

英文:

I'm investigating the channels behaviour and I'm quite confused by their behaviour. The spec say After calling close, and after any previously sent values have been received, receive operations will return the zero value for the channel&#39;s type without blocking. However it seems I still get the values in the range statement even if by that time the channel is closed. Why is that?

package main

import &quot;fmt&quot;
import &quot;sync&quot;
import &quot;time&quot;

func main() {
	iCh := make(chan int, 99)
	var wg sync.WaitGroup
	go func() {
		for i := 0; i &lt; 5; i++ {
			wg.Add(1)
			go func(i int) {
				defer wg.Done()
				iCh &lt;- i
			}(i)

		}
		wg.Wait()
		close(iCh)
	}()
	time.Sleep(5 * time.Second)
	print(&quot;the channel should be closed by now\n&quot;)
	for i := range iCh {
		fmt.Printf(&quot;%v\n&quot;, i)
	}
	print(&quot;done&quot;)
}

Edit: It seems that if I move the close statement just before the channel range it closes it for good. So I'm wondering why it's not working with the "time.Sleep" trick too . By that time (5 seconds) all the go routines should have been completed and the channel closed, isn't it ?

答案1

得分: 31

《Go编程语言规范》

关闭通道c的内置函数close(c)表示不会再向该通道发送更多的值。
在调用close之后,并在接收到之前发送的任何值之后,接收操作将返回该通道类型的零值,而不会阻塞。

在通道缓冲区中,有5个先前发送的值,然后是一个关闭操作。

例如,

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	iCh := make(chan int, 99)
	var wg sync.WaitGroup
	go func() {
		for i := 0; i < 5; i++ {
			wg.Add(1)
			go func(i int) {
				defer wg.Done()
				iCh <- i
			}(i)

		}
		wg.Wait()
		close(iCh)
	}()

	time.Sleep(5 * time.Second)
	fmt.Println("先前发送的值数量:", len(iCh))
	for i := range iCh {
		fmt.Printf("%v\n", i)
	}
	print("通道现在应该已关闭\n")
	print("完成")
}

输出:

先前发送的值数量: 5
0
1
2
3
4
通道现在应该已关闭
完成
英文:

> The Go Programming Language Specification
>
> Close
>
> For a channel c, the built-in function close(c) records that no more
> values will be sent on the channel.
> After calling close, and after any previously sent values have been
> received, receive operations will return the zero value for the
> channel's type without blocking.

In the channel buffer there are 5 previously sent values followed by a close.

For example,

package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

func main() {
	iCh := make(chan int, 99)
	var wg sync.WaitGroup
	go func() {
		for i := 0; i &lt; 5; i++ {
			wg.Add(1)
			go func(i int) {
				defer wg.Done()
				iCh &lt;- i
			}(i)

		}
		wg.Wait()
		close(iCh)
	}()

	time.Sleep(5 * time.Second)
	fmt.Println(&quot;previously sent values&quot;, len(iCh))
	for i := range iCh {
		fmt.Printf(&quot;%v\n&quot;, i)
	}
	print(&quot;the channel should be closed by now\n&quot;)
	print(&quot;done&quot;)
}

Output:

previously sent values 5
0
1
2
3
4
the channel should be closed by now
done

huangapple
  • 本文由 发表于 2015年3月26日 10:01:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/29269850.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定