系列文章目录
异常处理(defer recover panic)
Go-channel的妙用
文章目录
- 系列文章目录
- 前言
- 一、channel 通过通讯共享内存
- 二、使用场景
- 三、例子
- 1.包
- 总结
前言
Go语言中,各个协程之间的通信,Go 语言协程之间通信的理念通过通信去共享内存。就是采用channel 技术实现。
一、channel 通过通讯共享内存
- channel的方向, 读、写、读写;
- channel 协程间通信信道;
- channel 阻塞协程;
- channel 并发场景下的同步机制;
- channel 通知协程退出;
- channel 的多路复用; 借助于select监听,channel阻塞在select ,
二、使用场景
- 协程间通信,即协程间数据传输;
- 并发场景下利用channel的阻塞机制,作为同步机制(类似队列);例如并发打印日志,可以把并发写日志请求写入channel,然后使用另个一协程在读取channel 中请求,写日志。
- 利用channel关闭时发送广播的特性,作为协程退出通知;channel 关闭的时候,会向所有监听它的协程发送一个零值。
三、例子
1.包
代码如下(示例):case/channel.go
package _caseimport ("fmt""time"
)// 协程间通信
func Communication() {// 定义一个可读可写的通道ch := make(chan int, 0)go communicationF1(ch)go communicationF2(ch)
}// F1接受一个只写通道
func communicationF1(ch chan<- int) {// 通过循环向通道写入0~99for i := 0; i < 99; i++ {ch <- i}
}// F1接受一个只读通道
func communicationF2(ch <-chan int) {// 通过循环向通道写入0~99for i := range ch {fmt.Println(i)}
}// 并发场景下的同步机制
func ConcurentSync() {//带缓冲的通道 chan 带10个缓存,可以并发写入10个,写满后阻塞,只有读出后才能狗写入ch := make(chan int, 10)// 向chan 写入数据go func() {for i := 0; i < 100; i++ {ch <- i}}()// 向chan 写入数据go func() {for i := 0; i < 100; i++ {ch <- i}}()// 从chan 中读取数据go func() {for i := range ch {fmt.Println(i)}}()
}// 通知协程退出,多路复用
func NoticeAndMultiplexing() {ch := make(chan int, 0)strCh := make(chan string, 0)done := make(chan struct{}, 0)go noticeAndMultiplexingF1(ch)go noticeAndMultiplexingF2(strCh)go noticeAndMultiplexingF3(ch, strCh, done)time.Sleep(5 * time.Second)close(done) // 关闭done 时候会向所有监听它的协程发送一个零值。
}func noticeAndMultiplexingF1(ch chan<- int) {for i := 0; i < 100; i++ {ch <- i}
}func noticeAndMultiplexingF2(ch chan<- string) {for i := 0; i < 100; i++ {ch <- fmt.Sprintf("数字:%d", i)}}// select 子句作为一个整体阻塞,其中任意channel 准备就绪则继续执行
func noticeAndMultiplexingF3(ch <-chan int, strCh <-chan string, done <-chan struct{}) {i := 0for {select {case i := <-ch:fmt.Println(i)case str := <-strCh:fmt.Println(str)case <-done:fmt.Println("收到退出通知,退出当前协程")return}i++fmt.Println("累计执行次数: ", i)}}代码如下(示例):main.c```c
package mainimport (_case "channel-select/case""os""os/signal"
)func main() {//_case.Communication()//_case.ConcurentSync()_case.NoticeAndMultiplexing()ch := make(chan os.Signal, 0)signal.Notify(ch, os.Interrupt, os.Kill) //ctr+c 或kill 时候往channel 中写入信号量<-ch // 从 ch 中读取数据,数据内容不关心,只要有信号意味着系统退出了,没有值读出就是阻塞到这里
}
总结
注意: channel 用于
协程间通讯,必须存在读写双方,否则将造成死锁
。