# 信道/Channels
信道是一个类型管道,你可以用操作符 <-,实现数据的发送和接受。
// 发送v 到ch 信道
ch <- v
// 声明变量v,值从信道ch中获得
v := <-ch
观察上述代码可以发现,数据的方向也就是操作符箭头的方向。
信道也可用用make创建
ch := make(chan int)
默认情况下,信道会等数据完成之后才开始发送或接受。这样就可以免去开发者,手动编写控制锁或者条件语句。
# 示例
假如现在存在一个切片s,需要分别计算它前后一半的数值总和。我们用两个GO程来实现
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
fmt.Println(v)
}
fmt.Println(s)
c <- sum // 将和送入 c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // 从 c 中接收
fmt.Println(x, y, x+y)
}
输出结果:
-9
4
0
[-9 4 0]
7
2
8
[7 2 8]
-5 17 12
可以看到,尽管我们用了GO程,但输出的结果顺序如在同一个协程一样。 因为的第一次执行sum时,程序发现信道需要写入。因此会等第一次sum执行完之后,才开始执行第二次的sum。因此在这个例子中,虽然我们用了两个GO 程,但实际程序运行时,并没有分别同时执行2个sum。
# 关闭信道
通道本身并不提供关闭通道的方法,而是通过系统内置的close()方法关闭通道。在通道关闭后再继续往通道写数据会引发panic错误,而读数据则可以持续读取到通道中没有值为止,读取通道支持多参数返回,其中第一个参数表示从通道中读出的值,第二个参数表示是否正确读出数据,在通道关闭的情况下会返回false,可以借此判断通道是否已经关闭
package main
import (
"fmt"
)
func main() {
// 创建一个通道
msgChan := make(chan string, 10)
// 先往通道写入一条记录
msgChan <- "a normal message"
// 关闭通道
close(msgChan)
// 持续从通道中读取数据,ok值为false时,表示通道已经关闭且没有数据
for {
msg, ok:= <-msgChan
if !ok {
fmt.Println("chan already closed")
return
}
fmt.Printf("message: %s\n", msg)
}
}
# 单向信道
正常情况下,信道是双向的,既可读也可用写。但出于安全考虑,在某些情况下,我们可能会用到单向的信道。单向可以由双向通道转换,但不能转换回双向通道。 它的定义方式如下:
//定义只读通道:
var <-chan {通道类型}
//定义只写通道:
var chan<- {通道类型}
← Go程/Gorouttine 并发 →