完成14.2

This commit is contained in:
glight2000
2015-12-28 23:36:19 +08:00
parent 7d7b6393e1
commit c1466e58c9

View File

@@ -456,7 +456,175 @@ func (c *container) Iter () <- chan items {
return ch return ch
} }
``` ```
在协程里一个for循环迭代容器c中的元素对于树或图的算法这种简单的for循环可以替换为深度优先搜索
调用这个方法的代码可以这样迭代容器:
```go
for x := range container.Iter() { ... }
```
可以运行在自己的协程中,所以上边的迭代用到了一个通道和两个协程(可能运行在两个线程上)。就有了一个特殊的生产者-消费者模式。如果程序在协程给通道写完值之前结束协程不会被回收设计如此。这种行为看起来是错误的但是通道是一种线程安全的通信。在这种情况下协程尝试写入一个通道而这个通道永远不会被读取这可能是个bug而并非期望它被静默的回收。
习惯用法:生产者消费者模式
假设你有`Produce()`函数来产生`Consume`函数需要的值。它们都可以运行在独立的协程中,生产者在通道中放入给消费者读取的值。整个处理过程可以替换为无限循环:
```go
for {
Consume(Produce())
}
```
## 14.2.11 通道的方向
通道类型可以用注解来表示它只发送或者只接收:
```go
var send_only chan<- int // channel can only receive data
var recv_only <-chan int // channel can onley send data
```
只接收的通道(<-chan T无法关闭因为关闭通道是发送者用来表示不再给通道发送值了所以对只接收通道是没有意义的通道创建的时候都是双向的但也可以分配有方向的通道变量就像以下代码
```go
var c = make(chan int) // bidirectional
go source(c)
go sink(c)
func source(ch chan<- int){
for { ch <- 1 }
}
func sink(ch <-chan int) {
for { <-ch }
}
```
习惯用法管道和选择器模式
更具体的例子还有协程处理它从通道接收的数据并发送给输出通道
```go
sendChan := make(chan int)
reciveChan := make(chan string)
go processChannel(sendChan, receiveChan)
func processChannel(in <-chan int, out chan<- string) {
for inValue := range in {
result := ... /// processing inValue
out <- result
}
}
```
通过使用方向注解来限制协程对通道的操作
这里有一个来自Go指导的很赞的例子打印了输出的主要数字使用选择器作为它的算法每个素数都有一个选择器如下图
![](../images/14.2_fig14.2.png?raw=true)
版本1 示例 14.7-[sieve1.go](examples/chapter_14/sieve1.go)
```go
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.package main
package main
import "fmt"
// Send the sequence 2, 3, 4, ... to channel 'ch'.
func generate(ch chan int) {
for i := 2; ; i++ {
ch <- i // Send 'i' to channel 'ch'.
}
}
// Copy the values from channel 'in' to channel 'out',
// removing those divisible by 'prime'.
func filter(in, out chan int, prime int) {
for {
i := <-in // Receive value of new variable 'i' from 'in'.
if i%prime != 0 {
out <- i // Send 'i' to channel 'out'.
}
}
}
// The prime sieve: Daisy-chain filter processes together.
func main() {
ch := make(chan int) // Create a new channel.
go generate(ch) // Start generate() as a goroutine.
for {
prime := <-ch
fmt.Print(prime, " ")
ch1 := make(chan int)
go filter(ch, ch1, prime)
ch = ch1
}
}
```
协程`filter(in, out chan int, prime int)`拷贝整数到输出通道丢弃掉可以被prime整除的数字然后每个prime又开启了一个新的协程生成器和选择器并发请求
```
输出2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101
103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223
227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349
353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479
487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619
631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769
773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929
937 941 947 953 967 971 977 983 991 997 1009 1013...
```
第二个版本引入了上边的习惯用法函数`sieve`,`generate`,`filter`都是工厂它们创建通道并返回而且使用了协程的lambda函数`main`函数现在短小清晰它调用`sieve()`返回了包含素数的通道然后通过`fmt.Println(<-primes)`打印出来
版本2示例 14.8-[sieve2.go](examples/chapter_14/sieve2.go)
```go
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
)
// Send the sequence 2, 3, 4, ... to returned channel
func generate() chan int {
ch := make(chan int)
go func() {
for i := 2; ; i++ {
ch <- i
}
}()
return ch
}
// Filter out input values divisible by 'prime', send rest to returned channel
func filter(in chan int, prime int) chan int {
out := make(chan int)
go func() {
for {
if i := <-in; i%prime != 0 {
out <- i
}
}
}()
return out
}
func sieve() chan int {
out := make(chan int)
go func() {
ch := generate()
for {
prime := <-ch
ch = filter(ch, prime)
out <- prime
}
}()
return out
}
func main() {
primes := sieve()
for {
fmt.Println(<-primes)
}
}
```
## 链接 ## 链接