Files
the-way-to-go_ZH_CN/eBook/14.3.md
2015-12-30 22:34:57 +08:00

111 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 14.3 协程的同步:关闭通道-测试阻塞的通道
通道可以被显示的关闭;尽管它们和文件不同:不必每次都关闭。只有在当需要告诉接收者不会再提供新的值的时候,才需要关闭通道。只有发送者需要关闭通道,接收者永远不会需要。
继续看示例[goroutine2.go](examples/chapter_14/goroutine2.go)示例14.2):我们如何在通道的`sendData()`完成的时候发送一个信号,`getData()`又如何检测到通道是否关闭或阻塞?
第一个可以通过函数`close(ch)`来完成:这个将通道标记为无法通过发送操作<-接受更多的值给已经关闭的通道发送或者再次关闭都会导致运行时的panic在创建一个通道后使用defer语句是个不错的办法类似这种情况
```go
ch := make(chan float64)
defer close(ch)
```
第二个问题可以使用逗号ok操作符用来检测通道是否被关闭
如何来检测可以收到没有被阻塞或者通道没有被关闭
```go
v, ok := <-ch // ok is true if v received value
```
通常和if语句一起使用
```go
if v, ok := <-ch; ok {
process(v)
}
```
或者在for循环中接收的时候当关闭或者阻塞的时候使用break
```go
v, ok := <-ch
if !ok {
break
}
process(v)
```
可以通过`_ = ch <- v`来实现非阻塞发送因为空标识符获取到了发送给`ch`的任何东西在示例程序14.2中使用这些可以改进为版本goroutine3.go输出相同
实现非阻塞通道的读取需要使用select参见章节[14.4](14.4.md)
示例 14.9-[goroutine3.go](examples/chapter_14/goroutine3.go)
```go
package main
import "fmt"
func main() {
ch := make(chan string)
go sendData(ch)
getData(ch)
}
func sendData(ch chan string) {
ch <- "Washington"
ch <- "Tripoli"
ch <- "London"
ch <- "Beijing"
ch <- "Tokio"
close(ch)
}
func getData(ch chan string) {
for {
input, open := <-ch
if !open {
break
}
fmt.Printf("%s ", input)
}
}
```
改变了以下代码
* 现在只有`sendData()`是协程`getData()``main()`在同一个线程中
```go
go sendData(ch)
getData(ch)
```
* `sendData()`函数的最后关闭了通道
```go
func sendData(ch chan string) {
ch <- "Washington"
ch <- "Tripoli"
ch <- "London"
ch <- "Beijing"
ch <- "Tokio"
close(ch)
}
```
* 在for循环的`getData()`在每次接收通道的数据之前都使用`if !open`来检测
```go
for {
input, open := <-ch
if !open {
break
}
fmt.Printf("%s ", input)
}
```
使用for-range语句来读取通道是更好的办法因为这会自动检测通道是否关闭
```go
for input := range ch {
process(input)
}
```
阻塞和生产者-消费者模式
在章节14.2.10的通道迭代器中两个协程经常是一个阻塞另外一个如果程序工作在多核心的机器上大部分时间只用到了一个处理器可以通过使用带缓冲缓冲空间大于0的通道来改善比如缓冲大小为100迭代器在阻塞之前至少可以从容器获得100个元素如果消费者协程在独立的内核运行就有可能让协程不会出现阻塞
由于容器中元素的数量通常是已知的需要让通道有足够的容量放置所有的元素这样迭代器就不会阻塞尽管消费者协程仍然可能阻塞)。然后这样有效的加倍了迭代容器所需要的内存使用量所以通道的容量需要限制一下最大值记录运行时间和性能测试可以帮助你找到最小的缓存容量带来最好的性能
## 链接
- [目录](directory.md)
- 上一节[协程间的信道](14.2.md)
- 下一节[使用select切换协程](14.4.md)