channel 不仅能够控制数据传输,还可以控制执行流。
1. 关闭的channel从来都不会阻塞
关闭的channel不能传数据但是可以接受数据,例子
```
package mainimport "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 mainimport "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 mainimport (
"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 mainimport (
"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 mainimport (
"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 mainfunc main() {
var ch chan bool
ch <- true // blocks forever
}
```
这是一个死锁。
接受的话也是死锁。
```
package mainfunc main() {
var ch chan bool
<- ch // blocks forever
}
```
先看到这,明天再来。