奇怪的channel 的笔记

channel 不仅能够控制数据传输,还可以控制执行流。

1.  关闭的channel从来都不会阻塞

关闭的channel不能传数据但是可以接受数据,例子

```

package main

import "fmt"

func main() {
        ch := make(chan bool, 2)
        ch <- true
        ch <- true
        close(ch)

        for i := 0; i < cap(ch) +1 ; i++ {
                v, ok := <- ch
                fmt.Println(v, ok)
        }
}

```

 

接受的是默认空值。

替代性地,可以用range

```

package main

import "fmt"

func main() {
        ch := make(chan bool, 2)
        ch <- true
        ch <- true
        close(ch)

        for v := range ch {
                fmt.Println(v) // called twice
        }
}

```

当channel干枯后就会跳出循环流程,这个循环会执行两次。

 

但是select才是真功夫。

 

```

package main

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

func main() {
        finish := make(chan bool)
        var done sync.WaitGroup
        done.Add(1)
        go func() {
                select {
                case <-time.After(1 * time.Hour):
                case <-finish:
                }
                done.Done()
        }()
        t0 := time.Now()
        finish <- true // send the close signal
        done.Wait()    // wait for the goroutine to stop
        fmt.Printf("Waited %v for goroutine to stop\n", time.Since(t0))
}

```

 

在调用done之前是不会真的等一个小时的。

但是这个程序也会有问题。就是finish 不是带缓冲的。如果接受者忘了加上select里面的语句的话,就会阻塞了。(比如开了100个goroutine,但是这送了99次之类的)

利用关闭了的channel是永远可以接受的特性,把代码改成下面这样。

```

package main

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

func main() {
        const n = 100
        finish := make(chan bool)
        var done sync.WaitGroup
        for i := 0; i < n; i++ { 
                done.Add(1)
                go func() {
                        select {
                        case <-time.After(1 * time.Hour):
                        case <-finish:
                        }
                        done.Done()
                }()
        }
        t0 := time.Now()
        close(finish)    // closing finish makes it ready to receive
        done.Wait()      // wait for all goroutines to stop
        fmt.Printf("Waited %v for %d goroutines to stop\n", time.Since(t0), n)
}

```

话说这和没有finish通道不是一个效果么?不管了

实际上如果在通道里的东西,你从来不用,应该构造成空的结构体,就像下面的例子。

```

package main

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

func main() {
        finish := make(chan struct{})
        var done sync.WaitGroup
        done.Add(1)
        go func() {
                select {
                case <-time.After(1 * time.Hour):
                case <-finish:
                }
                done.Done()
        }()
        t0 := time.Now()
        close(finish)
        done.Wait()
        fmt.Printf("Waited %v for goroutine to stop\n", time.Since(t0))
}

```

 

说明这个channel不包含东西。

2.  nil channel 永远都是阻塞的。

```

package main

func main() {
        var ch chan bool
        ch <- true // blocks forever
}

```

这是一个死锁。

接受的话也是死锁。
```
package main

func main() {
        var ch chan bool
        <- ch // blocks forever
}

```

这个看起来不是很重要,但是可以用来的等待多个通道关闭。
```
// WaitMany waits for a and b to close.
func WaitMany(a, b chan bool) {
        var aclosed, bclosed bool
        for !aclosed || !bclosed {
                select {
                case <-a:
                        aclosed = true
                case <-b:
                        bclosed = true
                }
        }
}

```
这个函数能够等待两个通道关闭。

posted @ 2014-05-28 22:53  ggaaooppeenngg  阅读(467)  评论(0编辑  收藏  举报