这是一个死锁的例子

package mainimport ("fmt""sync"
)func main() {var (ch               chan intchInt01, chInt02 intsg               sync.WaitGroup)ch = make(chan int) //对于无缓存的通道channel,需要双方都准备好,才会发送,不然发送段会一直阻塞sg.Add(1)go func() {fmt.Println(666666)ch <- 1 //这里会等待channel接收端准备好,goroutine会阻塞在这里就是如ugo没有旁到读chan的地方此处会一致阻塞fmt.Println(11111)sg.Done()  }()fmt.Println(22222)sg.Wait() //由于ch<-1一致阻塞,导致没有机会调用sg.Done(),导致主协程一致等待,导致死锁chInt01 = <-chfmt.Println(33333)close(ch)chInt02 = <-chfmt.Println(11111, chInt01, chInt02)}

如果想达到预期,可以把sg.Done()提前

package mainimport ("fmt""sync"
)func main() {var (ch               chan intchInt01, chInt02 intsg               sync.WaitGroup)ch = make(chan int) //对于无缓存的通道channel,需要双方都准备好,才会发送,不然发送段会一直阻塞sg.Add(1)go func() {sg.Done() //提前到这里就解决了死锁问题fmt.Println(666666)ch <- 1 //这里会等待channel接收端准备好,goroutine会阻塞在这里就是如ugo没有旁到读chan的地方此处会一致阻塞fmt.Println(11111)}()fmt.Println(22222)sg.Wait() //由于ch<-1一致阻塞,导致没有机会调用sg.Done(),导致主协程一致等待,导致死锁chInt01 = <-chfmt.Println(33333)close(ch)chInt02 = <-chfmt.Println(11111, chInt01, chInt02)}

其实这里可以不使用sync.WaitGroup

package mainimport ("fmt"
)func main() {var (ch               chan intchInt01, chInt02 int)ch = make(chan int) //对于无缓存的通道channel,需要双方都准备好,才会发送,不然发送段会一直阻塞go func() {fmt.Println(666666)ch <- 1 //这里会等待channel接收端准备好,goroutine会阻塞在这里就是如ugo没有旁到读chan的地方此处会一致阻塞fmt.Println(11111)}()fmt.Println(22222)chInt01 = <-ch  //协程执行到这会阻塞等待写入fmt.Println(33333)close(ch)chInt02 = <-ch  //由于ch已经被读取,并且已经被关闭(如果没有被关闭,再次读取则会panic),所以读取到的值为int的零值fmt.Println(11111, chInt01, chInt02)
}
//执行结果:
//22222
//666666
//11111
//33333
//1 0

一般在写入端进行close,谁申请谁释放的原则

package mainimport ("fmt"
)func main() {var (ch               chan intchInt01, chInt02 int)ch = make(chan int) //对于无缓存的通道channel,需要双方都准备好,才会发送,不然发送段会一直阻塞go func() {fmt.Println(666666)ch <- 1 //这里会等待channel接收端准备好,goroutine会阻塞在这里就是如ugo没有旁到读chan的地方此处会一致阻塞close(ch)fmt.Println(11111)}()fmt.Println(22222)chInt01 = <-chfmt.Println(33333)chInt02 = <-chfmt.Println(chInt01, chInt02)
}
//22222
//666666
//11111
//33333
//1 0

如果是有缓存的时一样的

package mainimport ("fmt"
)func main() {var (ch               chan intchInt01, chInt02 int)ch = make(chan int,2) //对于无缓存的通道channel,需要双方都准备好,才会发送,不然发送段会一直阻塞go func() {fmt.Println(666666)ch <- 1 //这里会等待channel接收端准备好,goroutine会阻塞在这里就是如ugo没有旁到读chan的地方此处会一致阻塞ch <- 2close(ch)fmt.Println(11111)}()fmt.Println(22222)chInt01 = <-chfmt.Println(33333)chInt02 = <-chfmt.Println(chInt01, chInt02)
}
//22222
//666666
//11111
//33333
//1 2

也可以通过for range去读channel

package mainimport ("fmt"
)func main() {var (ch               chan intchInt01, chInt02 int)ch = make(chan int,2) //对于无缓存的通道channel,需要双方都准备好,才会发送,不然发送段会一直阻塞go func() {fmt.Println(666666)ch <- 1 //这里会等待channel接收端准备好,goroutine会阻塞在这里就是如ugo没有旁到读chan的地方此处会一致阻塞ch <- 2close(ch)fmt.Println(11111)}()fmt.Println(22222)for val := range ch{fmt.Printf("从ch读取的值:%v\n",val)}fmt.Println(33333)fmt.Println(chInt01, chInt02)
}
//22222
//666666
//11111
//从ch读取的值:1
//从ch读取的值:2
//33333
//0 0

总之:
0、channel是协程通信,单个协程没有意义,无缓存读写在一个协程会发生死锁,陷入等待
1、向已经关闭的channel发送数据都会保持panic,无论是否有缓存的channel
2、如果只有发送 ch<- 1,没有做接收端,有缓存的可以发送
3、如果只有发送 ch<- 1,没有做接收端,无缓存的channel不能发送,无缓存通道只有两端同时准备好才会发送数据,即同时读写,写完即读完
4、谁发送数据,谁close通道,谁申请谁释放的原则,发送端协程进行关闭最好
5、可以使用for val := range ch 或者for死循环来读取有缓存的值

有缓存的channel
0、有缓存的channel是个队列,尾部写入,头部读取
1、如果队列时满的,写入会阻塞到读取动作才会写入
2、如果队列时空的,读取操作会阻塞等待写入操作
3、只有队列不是满的也非空的时候向channel执行发送或者接收操作才都不会发生阻塞,此时可以解耦接收与发送的goroutine

无缓存与有缓存大小1的channel的区别
1、无缓存的,读写会相互等待,同时发生,先执行到的等待后执行的,需要不同协程读写,不然肯定会发生死锁问题,因为同一个协程肯定会发生有一个在前发生阻塞,等待不了后一个动作,总之无缓存channel写完即读完,同时发生
2、大小为1的channel 可以发生在同一个下协程,因为不要求读写同时发生

golang channel的一些总结相关推荐

  1. Golang channel 快速入门

    文章目录 1.简介 2.缓冲 channel 3.range 和 close 操作 4.select 操作 5.注意要点 6.常见用法 参考文献 1.简介 channel 提供了一种通信机制,通过发送 ...

  2. golang channel 管道 通道 信道 使用总结

    不同于传统的多线程并发模型使用共享内存来实现线程间通信的方式,golang 的哲学是通过 channel 进行协程(goroutine)之间的通信来实现数据共享: > Do not commun ...

  3. golang channel本质——共享内存

    channel是golang中很重要的概念,配合goroutine是golang能够方便实现并发编程的关键.channel其实就是传统语言的阻塞消息队列,可以用来做不同goroutine之间的消息传递 ...

  4. Golang channel 源码分析

    以下源码都摘自 golang 1.16.15 版本. 1. channel 底层结构 Golang 中的 channel 对应的底层结构为 hchan 结构体(channel的源码位置在Golang包 ...

  5. golang channel 管道 有无缓存的区别

    无缓冲的与有缓冲channel有着重大差别,那就是一个是同步的 一个是非同步的. 比如 c1:=make(chan int)         无缓冲 c2:=make(chan int,1)      ...

  6. golang channel 管道

    channel是Go中的一个核心类型,你可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯(communication). 它的操作符是箭头 <- . ch <- v ...

  7. golang channel的一点说明

    1.无缓存channel的就是同步.有缓存channel就是异步 2.channel最好还是关闭掉,不要等到gc回收 3.channel无缓存的时候,最好先准备读,然后另一个协程发起写,如果同步cha ...

  8. golang——channel笔记

    1.for i := range channel { //... } 相当于 循环进行 i<-channel,直至close(channel) 2. · 给一个 nil channel 发送数据 ...

  9. golang——channel

    目录 1.分类 channel的三种状态 channel的两种类型--有缓冲,无缓冲 无缓冲 有缓冲 2.操作 1.创建 2.发送 3.接收 4.关闭 3.使用场景 4.channel底层 5.cha ...

最新文章

  1. c语言spi发送12位数据,【51单片机】普通I/O口模拟SPI口C语言程序
  2. latex下IEEE模板中嵌套Python代码
  3. SWT 和 SWING
  4. android 加壳 方案,android加壳思路
  5. linux 760权限,Linux 文件rwx权限问题 chmod 777 XXX 任何人拥有最高权限
  6. 启动hbase后hregionserver没有启动
  7. python线上编辑问题_python django - static文件处理与线上部署测试
  8. Oracle 12c 安装及配置
  9. Git的使用教程(二)
  10. 使用Spring Security安全控制
  11. 正则表达式验证注册页面
  12. 身份证地区码数据表-SqlServer版
  13. 金三角图形c语言,升哥学堂 | 实战均线形态——“金三角”
  14. AutoIt上路03-添加工具栏
  15. CMAQ5.3安装笔记
  16. Java第十二周作业
  17. 写给产品经理的第4封信:关于产品经理的十万个为什么?你为什么要做产品经理?
  18. nafxcw.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined
  19. 六面体体积求解(规则不规则)
  20. 32 位 ARM® Cortex®-M0+内核 单片机

热门文章

  1. linux下基于源码软件安装的那些事
  2. [蓝桥杯][2019年第十届真题c/c++B组]迷宫(寻找路径bfs及文件输入输出)
  3. springboot项目如何不依赖spring-boot-parent
  4. Spring的注解形式:@Repository、@Service、@Controller
  5. linux有两种工作界面,Linux 向用户提供了两种界面:用户界面和系统调用。
  6. 《程序员代码面试指南》第一章 栈和队列 设计一个有getMin功能的栈
  7. mysql数据库从删库到跑路之mysq索引
  8. 楼市调控是安防行业是一门重要课题
  9. error C2220: 警告被视为错误 - 没有生成“object”文件
  10. Docker hello workd