channel的基本使用
2024-10-08 21:23:33
1、管道分类
- 读写管道
- 只读管道
- 只写管道
- 缓冲通道 :创建时指定大小(如果不指定默认为非缓冲通道)
2、正确使用管道
管道关闭后自能读,不能写
写入管道不能超过管道的容量cap,满容量还写则会阻塞
管道为空时,如果没有关闭,则继续读取会阻塞当前线程,直到有东西写入管道
m,ok:=<-intChan //ok用来检测产是否已经关闭 false代表关闭了,关闭了m就是默认值
一般如下操作才可以判断读取是否完毕,如果写进程没有关闭管道则说明还有东西要写
v,ok:=<-intChan
if !ok{
fmt.Println("读取完毕")
break
}
3、管道遍历与访问
- for-range访问
- select访问(常用)
for-range
//gor-range 如果管道没有数据同时还没有关闭 则会一直阻塞等待
go func() {
for i:=range c{ //注意这里没有ok判断是否关闭了 只有一个返回值
fmt.Println(i)
}
}()
下面这种情况for-range会阻塞,1秒后打印1,和 “关闭了”,如果没写同时又没有关闭,那么则会一直阻塞
ch := make(chan int)
go func() {
time.Sleep(time.Second)
//close(ch)
ch<-1
}()
go func() {
for i:=range ch{
log.Println(i)
}
log.Println("关闭了")
}()
time.Sleep(time.Hour)
下面的这种情况,for-range在一秒后会结束 ,同时打印“关闭了”
ch := make(chan int)
go func() {
time.Sleep(time.Second)
close(ch)
//ch<-1
}()
go func() {
for i:=range ch{
log.Println(i)
}
log.Println("关闭了")
}()
time.Sleep(time.Hour)
select
select会随机选择case里面没有阻塞的管道进行读取或写入,如果都阻塞则执行default语句,一般select都会伴随一个default语句
c:=make(chan string,2)
send:= func(v string) {
select {
case c<-v:log.Println("输入",v)
default:log.Println("缓冲区已经满")
}
}
receive:= func() string {
select {
case v:=<-c:return v
default:
log.Println("缓冲区空")
return ""
}
}
send("h1")
send("h2")
send("h3") //输入失败
log.Println(receive())
log.Println(receive())
log.Println(receive()) //取失败
当管道关闭时,select也会执行成功,如下打印了一秒‘等' 之后就会结束,这里没有往管道写东西,所以结束时打印的是默认值0
ch := make(chan int)
//go func() {
// ch <- 1
//}()
go func() {
time.Sleep(time.Second)
close(ch)
}()
go func() {
for {
time.Sleep(time.Microsecond*500)
select {
case v := <-ch:
log.Println(v)
return
default:
log.Println("等")
}
}
}()
time.Sleep(time.Hour)
4、阻塞情况
1、没有关闭,同时管道元素为0,读进程阻塞
2、没有关闭,同时管道元素已经满,则写进程阻塞,无缓冲管道的话则会阻塞在写,直到有人读
3、关闭管道,读光了还读,则读取出来的是对应类型管道的默认空值,在一个关闭通道进行写操作会报错
ch:=make(chan int,1)
ch<-1
close(ch)
log.Println(<-ch) //1
log.Println(<-ch) //0
log.Println(<-ch)//0
a,ok:=<-ch
log.Println(a,ok)//0 false
关闭管道,还写,则报错
无缓冲=堵塞,缓冲=非堵塞 无缓冲是同步,有缓冲是异步
像下面这个无缓冲管道,没人读则一直阻塞,只会打印A1,有一个管道读走了才会继续执行写操作,就比如快递员来发快递,只会等你拿走快递才会离开,否则一直在等你来拿
ch := make(chan int)
go func() {
for{
log.Println("A1")
time.Sleep(time.Second)
//close(ch)
ch<-1
log.Println("A2")
}
}()
那如果我把cap设置成1呢?
ch := make(chan int,1)
go func() {
for{
log.Println("A1")
time.Sleep(time.Second)
//close(ch)
ch<-1
log.Println("A2")
}
}()
打印如下,可以写一个
2020/03/21 20:02:59 A1
2020/03/21 20:03:00 A2
2020/03/21 20:03:00 A1
其他关于通道的使用可以看这两篇博客
go通道的常见使用场景.
go通道的优雅关闭.
最新文章
- vue transition
- UML 类图常用表示方法.
- Delphi编程获取系统当前进程、窗口句柄、文件属性以(转)
- WEB urllib2 module note
- Linux下Python获取IP地址
- Visual Studio 2015 和 Apache Cordova
- 序列dp笔记√
- linux解压cpio.gz类型文件
- Redis 使用 Eval 多个键值自增操作示例
- C/C++使用MySQL
- [源码分析]ReentrantLock &; AbstractQueuedSynchronizer &; Condition
- [Kubernetes]关于 Kubernetes ,你想要的,都在这儿了
- .NET Core中的路由约束
- POJ 2368 Buttons
- C# 中 FindControl 方法及使用
- vue2.0 element-ui中的el-select选择器无法显示选中的内容
- Node.js webpack Vue-CLI --安装
- GuavaCache学习笔记三:底层源码阅读
- right spindle supply short to gnd
- ps/kill/pkill简单应用
热门文章
- git clone 新项目时,报error: RPC failed; curl 18 transfer closed with outstanding read data remaining
- tips [ 18870 ]
- Seata-一站式分布式事务解决方案
- 自动贩卖机VS无人门店:谁是真正的零售新风口?
- 万达乐园VS阿里帝国 谁将是未来娱乐产业的龙头?
- C++走向远洋——43(人数不定的工资类,动态分配内存与释放)
- property 属性
- 关于地址栏url的一些小结
- vuex源码阅读分析
- 由一个项目需求引发的 - textarea中的换行和空格