1. 信道的概念
通过使用信道,数据也可以从一端发送,在另一端接收。
2. 信道的定义
所有信道都关联了一个类型。信道只能运输这种类型的数据,而运输其他类型的数据都是非法的。
chan T
表示 T
类型的信道。
信道的零值为 nil
。信道的零值没有什么用,应该像对 map 和切片所做的那样,用 make
来定义信道。例如:
a := make(chan int)
package main import ( "fmt" ) func main() { var a chan int if a == nil { fmt.Println("channel a is nil, going to define it") a = make(chan int) fmt.Printf("Type of a is %T", a) } }
运行结果:
3. 信道的发送和接收
data := <- a // 读取信道a,并将数据保存至data
a <- data // 将data数据写入信道a
注意: 信道的发送和接收是阻塞的。
package main import ( "fmt" ) func hello(done chan bool) { fmt.Println("Hello world goroutine") done <- true } func main() { done := make(chan bool) //创建信道 go hello(done) <-done fmt.Println("main function") }
运行结果:
4. 死锁
产生的原因:
1)一个go协程发送数据,没有其他协程接收数据
2)一个go协程等待接收数据,没有其他协程发送数据
package main func main() { ch := make(chan int) ch <- 5 }
执行结果:
5. 单向信道
创建一个只能发送数据的信道:
package main import "fmt" func sendData(sendch chan<- int) { sendch <- 10 } func main() { sendch := make(chan<- int) //创建一个只发送信道 go sendData(sendch) fmt.Println(<-sendch) //error:此处无法读取 }
执行结果:
6. 信道关闭
数据发送方可以关闭信道,通知接收方这个信道不再有数据发送过来。
当从信道接收数据时,接收方可以多用一个变量来检查信道是否已经关闭。
v, ok := <- ch //ok为false,则为读取一个关闭的信道
package main import ( "fmt" ) func producer(chnl chan int) { for i := 0; i < 10; i++ { chnl <- i } close(chnl) //close为关闭信道 } func main() { ch := make(chan int) go producer(ch) for { v, ok := <-ch if ok == false { break //信道关闭 直接跳出循环 } fmt.Println("Received ", v, ok) } }
执行结果:
注意:for range 循环用于在一个信道关闭之前,从信道接收数据。
package main import ( "fmt" ) func producer(chnl chan int) { for i := 0; i < 10; i++ { chnl <- i } close(chnl) } func main() { ch := make(chan int) go producer(ch) for v := range ch { fmt.Println("Received ", v) } }
执行结果:
7. 练习
计算一个数中每一位的平方和和立方和,然后将平方和和立方和相加并打印。
package main
import (
"fmt"
)
func digits(number int, dchnl chan int) {
for number != 0 {
digit := number % 10
dchnl <- digit
number /= 10
}
close(dchnl)
}
func calcSquares(number int, squareop chan int) {
sum := 0
dch := make(chan int)
go digits(number, dch)
for digit := range dch {
sum += digit * digit
}
squareop <- sum
}
func calcCubes(number int, cubeop chan int) {
sum := 0
dch := make(chan int)
go digits(number, dch)
for digit := range dch {
sum += digit * digit * digit
}
cubeop <- sum
}
func main() {
number := 589
sqrch := make(chan int)
cubech := make(chan int)
go calcSquares(number, sqrch)
go calcCubes(number, cubech)
squares, cubes := <-sqrch, <-cubech
fmt.Println("Final output", squares+cubes)
}
执行结果: