如何知道关闭是必要的?

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

How do I know close is necessary?

问题

有一些情况下你需要关闭通道,而有些情况下则不必要。

这里是一个需要关闭通道的例子:

queue := make(chan string, 2)
queue <- "one"
queue <- "two"
close(queue)

for elem := range queue {
    fmt.Println(elem)
}

在这个例子中,我得到了一个致命错误:所有的goroutine都处于休眠状态 - 死锁!

而这段代码中关闭通道是可选的:

jobs := make(chan int, 5)
done := make(chan bool)

go func() {
    for {
        j, more := <-jobs
        if more {
            fmt.Println("received job", j)
        } else {
            fmt.Println("received all jobs")
            done <- true
            return
        }
    }
}()

for j := 1; j <= 3; j++ {
    jobs <- j
    fmt.Println("sent job", j)
}
close(jobs)
fmt.Println("sent all jobs")

<-done
// close(done)

希望这些对你有帮助!

英文:

There are some cases you need to close channel and some cases that it is not necessary.

http://play.golang.org/p/piJHpZ2-aU

queue := make(chan string, 2)
queue &lt;- &quot;one&quot;
queue &lt;- &quot;two&quot;
close(queue)

for elem := range queue {
	fmt.Println(elem)
}

Here I am getting

fatal error: all goroutines are asleep - deadlock!

whereas this code's close is optional

http://play.golang.org/p/Os4T_rq0_B

jobs := make(chan int, 5)
done := make(chan bool)

go func() {
	for {
		j, more := &lt;-jobs
		if more {
			fmt.Println(&quot;received job&quot;, j)
		} else {
			fmt.Println(&quot;received all jobs&quot;)
			done &lt;- true
			return
		}
	}
}()

for j := 1; j &lt;= 3; j++ {
	jobs &lt;- j
	fmt.Println(&quot;sent job&quot;, j)
}
close(jobs)
fmt.Println(&quot;sent all jobs&quot;)

&lt;-done
// close(done)

答案1

得分: 6

第一个例子中,由于使用了range关键字,需要关闭通道。当range与通道一起使用时,它会继续尝试从通道中读取,直到通道关闭。

根据http://golang.org/ref/spec#For_statements的说明:

[使用range进行迭代时]...对于通道,产生的迭代值是连续发送到通道的值,直到通道关闭。如果通道为nil,则range表达式将永远阻塞。

这意味着你必须关闭通道才能退出循环。

在第二个例子中,你使用了接收操作符<-。这个操作符会阻塞,直到可以从通道中取出一个元素。由于通道中有一个等待被传递的元素,它会立即返回。在这种情况下,关闭通道是可选的,因为在此之后没有其他阻塞操作,所以保持通道"开放"也是可以的。

详见通道部分获取更多细节...

英文:

The first example the channel needs to be closed because of the usage of the range keyword. When range is used with a channel, it will continue to try to read from the channel until the channel is closed.

From http://golang.org/ref/spec#For_statements

> [When using range for] ...channels, the iteration values produced are the successive values sent on the channel until the channel is closed. If the channel is nil, the range expression blocks forever.

Which means that you have to close the channel to exit the loop.

In the second example you are using the receive operator &lt;-. This operator will block until one item can be pulled out of the channel. Since there is one item waiting in the channel to be delivered, it will yield immediately. In this case, close is optional because there are no other blocking operations on the channel after that, so it's just as happy to stay "open".

See the channels section for more details...

huangapple
  • 本文由 发表于 2013年11月3日 04:40:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/19746629.html
匿名

发表评论

匿名网友

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

确定