您现在的位置是:首页 >其他 >GO语言小锤硬磕.二十二 管道(channel)网站首页其他
GO语言小锤硬磕.二十二 管道(channel)
简介GO语言小锤硬磕.二十二 管道(channel)
1.认识channel
管道本质是一个队列(先进先出)
管道是线程安全的(自带锁)
管道解决协程中资源同步问题
2.声明和初始化Channel
package main
import "fmt"
func main(){
//1.声明管道 var 变量名 chan 数据类型
var mych chan int
//2.初始化管道 make(chan 数据类型,管道容量)
//管道和切片、字典一样make开辟存储空间后才能使用
//管道和切片、字典一样是引用类型
mych = make(chan int,3)
//3.查看管道的长度和容量
fmt.println("长度是",len(mych),"容量是",cap(mych))
//4.管道写入数据
mych<- 666
//5.取出管道中的数据
num := <-mych
//注意
1.管道中只能存放声明的数据类型。
2.主线程中管道中已经没有数据,并且检测不到其他线程写入数据,再取会报错。
3.主线程中管道数据已满,再写入也会报错。
}
3.管道的关闭和遍历
package main
import "fmt"
func main(){
//1.创建一个管道
mych := make(chan int,3)
//2.写入数据
mych<- 666
mych<- 777
mych<- 888
//3.关闭管道,关闭后只能读不能写
close(mych)
//4.使用for range 遍历管道。使用前必须先关闭管道否则会报deadlock的错误
//管道的遍历会弹出管道数据,长度会减少
for value := range mych{
fmt.Println(value)
}
//5.其他方式 ok-idiom模式读取管道,判断管道是否关闭,如果关闭会返回false给ok
for{
if num,ok:= <-mych; !ok{
break;
}else{
fmt.Println(num)
}
}
//6.误区
管道正常读取一次,内容会弹出,长度(len(mych))会减少1
//for i:=0; i<len(mych); i++ { //不正确
}
4.Channel阻塞现象
单独在主线程中操作管道,写满了会报错,没有数据去获取也会报错
只要在协程中操作管道过,写满了就会阻塞,没有数据去获取也会阻塞
5.使用Channe实现生产者消费者
package main
import(
"fmt"
"math/rand"
"time"
)
//定义缓冲区
var mych = make(chan int,5)
var exitch = make(chan bool,1)
//定义生产者
func producer(){
rand.Seed(time.Now().UnixNano())
for i:=0;i<10;i++{
num:=rand.Intn(100)
fmt.Println("生产者生产",num)
//写入管道
mych<-num
}
//生产完毕关闭管道
close(mych)
fmt.Println("生产者停止生产")
}
//定义消费者
func consumer(){
//不断从管道中获取数据,直到管道关闭
for{
if num,ok := <-mych;!ok{
break
}else{
fmt.Println("消费了",num)
}
}
fmt.Println("消费者停止消费")
exitch<-true
}
func main(){
go producer()
go consumer()
fmt.Println("exitch之前代码")
<-exitch
fmt.Println("exitch之后代码")
}
6.无缓冲Channel
package main
import "fmt"
var mych1 = make(chan int,5) //无缓冲区
var mych2 = make(chan int,0) //无缓冲区
fuc mian(){
//无缓冲区,需要在子程中提前埋入读取,而后写入
go func(){ //1.使用匿名函数建立协程
fmt.Println(<-mych2) //2.读取,读取到打印,读取不到线程挂起
}()
mych2<-1 //3.写入
//注意
//写入后在同一个线程读取会报错
//fmt.Println(<-mych2)
//在主程中先写入,在子程中后读取也会报错
}
7.有缓冲管道和无缓冲管道
有缓冲管道具备异步打的能力(写几个读一个或读几个)
无缓冲管道具备同步的能力(写一个读一个)
8.单向管道和双向管道
默认情况下所有的管道都是双向的
单向管道应用于管道作为参数传递时,限制管道的写入和读取权限。
双向管道 var mych chan int = make(chan int,0)
只写管道var mych chan<- int = make(chan<- int,0)
只读管道var mych <-chan int = make(<-chan int,0)
双向管道可以转换为任意一种单向管道,单向管道不能转换为双向管道
package main
import "fmt"
func main(){
//1.定义一个双向管道
var mych chan int = make(chan int,5)
//2.双向管道转单向
var mych1 chan<- int
mych1=mych
var mych2 <-chan int
mych2=mych
//3.注意 管道之间赋值是地址传递,以上三个管道底层指向相同容器
}
9.单向管道作为函数参数
package main
import(
"fmt"
"math/rand"
"time"
)
//定义生产者
func producer(mych chan<- int){
rand.Seed(time.Now().UnixNano())
for i:=0;i<10;i++{
num:=rand.Intn(100)
fmt.Println("生产者生产",num)
//写入管道
mych<-num
}
//生产完毕关闭管道
close(mych)
fmt.Println("生产者停止生产")
}
//定义消费者
func consumer(mych <-chan int){
//不断从管道中获取数据,直到管道关闭
for{
if num,ok := <-mych;!ok{
break
}else{
fmt.Println("消费了",num)
}
}
fmt.Println("消费者停止消费")
}
func main(){
var mych = make(chan int,5)
go producer(mych)
consumer(mych)
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。