Golang学习笔记–Channel
如何定义使用
定义
每个通道都有与之关联的类型。此类型是允许通道传输的数据类型。不允许使用该通道传输其他类型的数据。
通道的零值为nil。零通道没有任何用处,因此必须使用类似于 map 和 slice 的make来定义。
package main import "fmt" func main() { var a chan int // 定义 channel 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) // 输出Type of a is chan int } }
使用(接收和发送消息)
data := <- a // read from channel a a <- data // write to channel a
默认情况下,发送和接收到通道处于阻塞状态。当数据发送到通道时,主goroutine将在send语句中被阻塞,直到其他Goroutine从该通道读取数据为止。同样,当从通道读取数据时,将阻止读取,直到某些Goroutine将数据写入该通道为止。
此属性可帮助Goroutines有效通信,而无需使用其他编程语言中很常见的显式锁或条件变量。
一个简单的程序:
程序实现
(1 * 1) + (2 * 2) + (3 * 3) + ... (n * n) + (1 * 1 * 1) + (2 * 2 * 2) + (3 * 3 * 3) + ...(n * n * n)
可以拆成两部分并发执行,一个 goroutine 计算平方和,一个计算立方和
package main import ( "fmt" ) func calcSquares(number int, squareop chan int) { sum := 0 for number != 0 { digit := number % 10 sum += digit * digit number /= 10 } squareop <- sum } func calcCubes(number int, cubeop chan int) { sum := 0 for number != 0 { digit := number % 10 sum += digit * digit * digit number /= 10 } cubeop <- sum } func main() { number := 10 sqrch := make(chan int) cubech := make(chan int) go calcSquares(number, sqrch) go calcCubes(number, cubech) squares, cubes := <-sqrch, <-cubech // 利用 channel 使主 goroutine 等待结果 fmt.Println("Final output", squares + cubes) }
死锁
有一个地方需要注意,在使用 channel 时可能会引发死锁,看下面一个例子
func main() { ch := make(chan int) ch <- 5 }
这段程序向 channel 发送数字5,但是没有接收方,所以会一直阻塞
单向通道
上述简单的例子展示了 双向 channel 如何使用,但是也可以创建单向通道,即仅发送或接收数据的通道。
// 定义只发送channel sendch := make(chan<- int)
但是这样做又有什么意义呢,无法从 channel 中读取数据。 这是使用 channel 转换。可以将双向通道转换为仅发送或仅接收通道,反之亦然。
// 这里将 channel 转换为单项只发送 func sendData(sendch chan<- int) { sendch <- 10 } func main() { // 定义一个双向 channel chnl := make(chan int) go sendData(chnl) fmt.Println(<-chnl) }
关闭通道
发送者可以关闭该通道,以通知接收者该通道将不再发送任何数据。接收器可以在从通道接收数据时使用附加变量,以检查通道是否已关闭。
v, ok := <- ch
在上面的语句中,如果该值是通过对通道的成功发送操作接收到的,则ok为真。如果ok为假,则表示我们正在从封闭的通道读取数据。从关闭的通道读取的值将是通道类型的零值。例如,如果通道是int通道,则从封闭通道接收的值将为0。
channel 和 for range 可以搭配使用
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 { // 若channel 未关闭,则一直取数据 fmt.Println("Received ",v) } }
如果喜欢,请关注我的公众号,或者查看我的博客 http://packyzbq.coding.me . 我会不定时的发送我自己的学习记录,大家互相学习交流哈~

weixin