Ver Fonte

Update 14.3.md

glight2000 há 10 anos atrás
pai
commit
dab7a34ab6
1 ficheiros alterados com 109 adições e 0 exclusões
  1. 109 0
      eBook/14.3.md

+ 109 - 0
eBook/14.3.md

@@ -1 +1,110 @@
 # 协程的同步:关闭通道-测试阻塞的通道
+
+通道可以被显示的关闭;尽管它们和文件不同:不必每次都关闭。只有在当需要告诉接收者不会再提供新的值的时候,才需要关闭通道。只有发送者需要关闭通道,接收者永远不会需要。
+
+继续看示例[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)
+}
+```
+阻塞和生产者-消费者模式:
+
+
+
+
+
+## 链接
+
+- [目录](directory.md)
+- 上一节:[协程间的信道](14.2.md)
+- 下一节:[使用select切换协程](14.4.md)