# ### Channel使用技巧

#### 前言

Go协程一般使用channel（通道）通信从而协调/同步他们的工作。合理利用Go协程和channel能帮助我们大大提高程序的性能。本文将介绍一些使用channel的场景及技巧

#### 场景一，使用channel返回运算结果

package main

import (
"fmt"
"time"
)
//计算斐波那契数列并写到ch中
func fibonacci(n int, ch chan<- int) {
first, second := 1, 1
for i := 0; i < n; i++ {
ch <- first
first, second = second, first+second
}
close(ch)
}

func main() {
ch := make(chan int, 40)
i := 0
start := time.Now()
go fibonacci(cap(ch), ch)
for result := range ch {
fmt.Printf("fibonacci(%d) is: %d\n", i, result)
i++
}
end := time.Now()
delta := end.Sub(start)
fmt.Printf("took the time: %s\n", delta)
}

fibonacci(33) is: 5702887
fibonacci(34) is: 9227465
fibonacci(35) is: 14930352
fibonacci(36) is: 24157817
fibonacci(37) is: 39088169
fibonacci(38) is: 63245986
fibonacci(39) is: 102334155
took the time: 8.0004ms

#### 场景二，使用channel获取多个并行方法中的一个结果

func Query(conns []conn, query string) Result {
ch := make(chan Result, 1)
for _, conn := range conns {
go func(c Conn) {
select {
case ch <- c.DoQuery(query):
}
}(conn)
}
return <- ch
}

#### 场景三，响应超时处理

func CallWithTimeOut(timeout time.Duration) (int, error) {
select {
case resp := <-Call():
return resp, nil
case <-time.After(timeout):
return -1, errors.New("timeout")
}
}

func Call() <-chan int {
outCh := make(chan int)
go func() {
//调用远程方法
}()
return outCh
}

func ReadWithTimeOut(ch <-chan int) (x int, err error) {

select {
case x = <-ch:
return x, nil
case <-time.After(time.Second):
}

}
func WriteWithTimeOut(ch chan<- int, x int) (err error) {
select {
case ch <- x:
return nil
case <-time.After(time.Second):
}
}

#### 场景四，多任务并发执行和顺序执行

package main

import (
"fmt"
"time"
)

func B(quit chan<- string) {
fmt.Println("B crraied out")
quit <- "B"
}

func A(quit chan<- string, finished chan<- bool) {
// 模拟耗时任务
time.Sleep(time.Second * 1)
fmt.Println("A crraied out")
finished <- true
quit <- "A"
}

func C(quit chan<- string, finished <-chan bool) {
// 在A没有执行完之前，finished获取不到数据，会阻塞
<-finished
fmt.Println("C crraied out")
quit <- "C"
}

func main() {
finished := make(chan bool)
defer close(finished)
quit := make(chan string)
defer close(quit)

go A(quit, finished)
go B(quit)
go C(quit, finished)

fmt.Println(<-quit)
fmt.Println(<-quit)
fmt.Println(<-quit)
}

for res := range quit {
fmt.Println(res)
}
fatal error: all goroutines are asleep - deadlock!
原因很简单，程序中quit通道没有被close，A、B、C运行完了，Go的主协程在for循环中阻塞了，所有Go协程都阻塞了，进入了死锁状态