我是靠谱客的博主 名字长了才好记,这篇文章主要介绍go channel,现在分享给大家,希望可以做个参考。

之前的goroutine都是作用在函数上测试的,但很多时候各个函数之间需要相互传输数据,那么就需要用到channel通道。channel是安全的,不会发生死锁等问题。

goroutine和channel往往结合使用,channel连接了不同的goroutine,使其相互传输数据。


定义


channel是一个引用类型,类似队列,遵循的是先进先出规则,声明格式:var username chan type。


如以下示例:


复制代码
1
// 声明一个传递整形的通道
var ch1 chan int
// 声明一个传递int切片的通道
var ch2 chan []int


创建


channel声明后需要进行make初始化才可使用,不声明则为空值nil。


复制代码
1
2
3
4
5
6
func main() { var ch chan int fmt.Println(ch) // nil ch1 := make(chan int, 3) fmt.Println(ch1) // 0xxxxxxxx }


channel有三种操作,分别是发送、接收、关闭。发送和接收都使用<-符号。


例如有一个ch通道。


使用ch通道发送数据为:ch <- 10

接收ch通道发出的数据为:a := <- ch,如果要忽略通道发出的数据,则什么都不写即可:<- ch

关闭ch通道:close(ch)


关闭通道需要注意:只有告诉接收方所有的数据都发送完毕,才需关闭通道,而通道是可以被垃圾回收机制回收的,所以不关也可以。


示例:


复制代码
1
2
3
4
5
6
7
8
func main() { ch := make(chan int, 3) // 这时ch通道没有任何数据,所以接收时会报deadlock错误 a := <-ch fmt.Println(a) ch <- 10 b := <-ch fmt.Println(b) // 10 }


无缓冲区通道


无缓冲区通道即初始化时没有指定该通道的容量大小。


复制代码
1
2
3
4
5
func main() { ch := make(chan int) ch <- 10 fmt.Println("success") }


上面就是一个无缓冲区通道的例子,make时没有定义通道大小,运行时会报deadlock错误,因为无缓冲区通道无法发送数据,所以程序会阻塞在ch <- 10这一行,造成死锁。


解决办法就是通过启用goroutine去接收值,示例如下:


复制代码
1
2
3
4
5
6
7
8
9
10
func recv(c chan int) { ret := <-c fmt.Println("receive success", ret) } func main() { ch := make(chan int) go recv(ch) ch <- 10 fmt.Println("send success") }


注意:当从无缓冲区通道接受值时,该通道必须有值再发送。同理,发送值时,也必须有接收的。缺一不可,所以无缓冲区通道也叫同步通道,发送和接收是同步进行的。


有缓冲区通道


make初始化给了容量大小就是有缓冲区通道,可以使用len查看通道目前存有几个元素,cap查看通道的容量。


复制代码
1
2
3
4
5
6
7
8
9
10
func main() { ch := make(chan int, 3) ch <- 10 ch <- 20 fmt.Println(len(ch)) // 2 fmt.Println(cap(ch)) // 3 fmt.Println(<-ch) // 10 fmt.Println(<-ch) // 20 fmt.Println(len(ch)) }


通道遍历


通道遍历可以使用range,如下示例:


复制代码
1
2
3
4
5
6
7
8
9
10
func main() { ch := make(chan int, 10) for i := 0; i < 10; i++ { ch <- i } close(ch) for v := range ch { fmt.Println(v) } }


注意:ch通道在发送值后,使用close关闭了,如果此处不关闭,下面range遍历时就会报死锁,因为循环接收值时,接收完后,还会循环取,这时已经没值了,就会不断循环造成死锁,所以需要进行关闭。


单向通道


函数中允许参数为通道类型,但有时候可能只需要该通道来接收值或者发送值,这时就需要对该通道设置单向设置。设置时只需要在函数参数上添加<-符号即可。


复制代码
1
2
3
4
5
6
7
8
// a函数的通道参数只能传入值,即只写的单向通道 func a(ch chan<- int) { fmt.Println(ch) } // b函数的通道参数只能输出值,即只读的单向通道 func b(ch <-chan int) { fmt.Println(ch) }


示例如下:


复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func onlyWrite(ch chan<- int) { for i := 0; i < 10; i++ { ch <- i } close(ch) } func onlyRead(read <-chan int, write chan<- int) { for v := range read { write <- v } close(write) } func chPrint(ch <-chan int) { for v := range ch { fmt.Println(v) } } func main() { ch1 := make(chan int) ch2 := make(chan int) go onlyWrite(ch1) go onlyRead(ch1, ch2) chPrint(ch2) }

通道关闭的特点


1,通道关闭后,再发送值会导致panic异常。

2,通道关闭后,再接收值会一直进行数据的读取,直到读完。

3,通道关闭后,再进行关闭会导致panic异常。


通道总结


最后

以上就是名字长了才好记最近收集整理的关于go channel的全部内容,更多相关go内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(951)

评论列表共有 0 条评论

立即
投稿
返回
顶部