在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
前言goroutine是go语言程序的并发执行的基本单元,多个goroutine的通信是需要依赖channel,叫做信道 1.信道的定义与使用每个信道只能传递一种数据类型的数据,所以声明信道的时候,需要指定数据类型(string、int等) 信道实例 := make(chan 信道类型) 假如我要创建一个可以传递int数据类型的信道 //定义信道 pipline := make(chan int) 信道的数据操作,无非就是两种:发送数据和读取数据 // 往信道中发送数据 pipline<- 200 // 从信道中取出数据,并赋值给mydata mydata := <-pipline 信道用完了,可以对其进行关闭,避免有人一直在等待 close(pipline) 对于一个已经关闭的信道 如果再去关闭是会报错的,所以我们需要判断一下 信道 是不是被关闭 当从信道读取数据时,可以有多个返回值,其中第二个可以表示信道是否被关闭,如果已经被关闭就返回false,如果还没被关闭返回true x, ok := <-pipline 2.信道的容量和长度一般创建信道都是使用make函数,make函数接收两个参数 第一个参数: 必填 必定信道类型 第二个参数: 选填 不填默认为0,指定信道的容量(可以缓存多少数据) 对于信道的容量很重要:
我们现在知道 信道就是一个容器 如果将它比作一个纸箱子
信道的容量可以用cap()函数获取,信道的长度可以用len()函数来获取 package main import "fmt" func main() { pipline := make(chan int, 10) fmt.Printf("信道可缓冲 %d 个数据\n", cap(pipline)) pipline<- 1 fmt.Printf("信道中当前有 %d 个数据", len(pipline)) } 输出如下 信道可缓冲 10 个数据 信道中当前有 1 个数据 3.缓冲信道和无缓冲信道按照是否可缓冲数据可分为:缓冲信道和无缓冲信道 缓冲信道 允许信道里存储一个或多个数据,这意味着,设置了缓冲区后,发送端和接收端可以处于异步的状态 pipline := make(chan int, 10) 无缓冲信道 在信道里无法存储数据,这意味着,接收端必须先于发送端准备好,以确保你发送完数据和,有人立马接收数据,否则发送端就会造成阻塞 原因很简单,信道中无法存储数据;也就是说发送端和接收端是同步运行的 pipline := make(chan int) // 或者 pipline := make(chan int, 0) 4.双向通道和单向通道通常情况下,我们定义的都是双向信道,可以发送数据,也可以接收数据 但有时候,我们希望对信道的数据流做一些控制,比如这个信道只能接收数据或者这个信道只能发送数据 因此就有了双向信道和单向信道两种分类 4.1双向信道 默认情况下你定义的信道都是双向的,比如下面代码 import ( "fmt" "time" ) func main() { pipline := make(chan int) go func() { fmt.Println("准备发送数据: 100") pipline <- 100 }() go func() { num := <-pipline fmt.Printf("接收到的数据是: %d", num) }() // 主函数sleep,使得上面两个goroutine有机会执行 time.Sleep(1) } 4.2单向信道 可以细分为只读信道和只写信道 定义只度信道 var pipline = make(chan int) type Receiver = <-chan int // 关键代码:定义别名类型 var receiver Receiver = pipline 定义只写信道 var pipline = make(chan int) type Sender = chan<- int // 关键代码:定义别名类型 var sender Sender = pipline 仔细观察区别在于<-符号在关键字chan的左边还是右边
为什么要先定义一个双向信道,在定义一个单向信道呢,比如这样写 import ( "fmt" "time" ) //定义只写信道类型 type Sender = chan<- int //定义只读信道类型 type Receiver = <-chan int func main() { var pipline = make(chan int) go func() { var sender Sender = pipline fmt.Println("准备发送数据: 100") sender <- 100 }() go func() { var receiver Receiver = pipline num := <-receiver fmt.Printf("接收到的数据是: %d", num) }() // 主函数sleep,使得上面两个goroutine有机会执行 time.Sleep(1) } 信道本身就是为了传输数据而存在的,如果只有接收者或者只有发送者,那信道就变成了只入不出或者只出不入,那就没意义了. 5.遍历信道遍历信道,可以搭配使用for搭配range关键字,在range时,要确保信道处于关闭状态,否则循环会阻塞
import "fmt" func fibonacci(mychan chan int) { n := cap(mychan) x, y := 1, 1 for i := 0; i < n; i++ { mychan <- x x, y = y, x+y } // 记得 close 信道 // 不然主函数中遍历完并不会结束,而是会阻塞。 close(mychan) } func main() { pipline := make(chan int, 10) go fibonacci(pipline) for k := range pipline { fmt.Println(k) } }
当容量为1时,说明信道只能缓存一个数据,若信道中已有一个数据,此时再往里发送数据,会造成程序阻塞。 利用这点可以利用信道来做锁 |
请发表评论