系列文章目录
Go-channel的妙用
前言
Go语言中,各个协程之间的通信,Go 语言协程之间通信的理念通过通信去共享内存。就是采用channel 技术实现。
一、channel 通过通讯共享内存
- channel的方向, 读、写、读写;
- channel 协程间通信信道;
- channel 阻塞协程;
- channel 并发场景下的同步机制;
- channel 通知协程退出;
- channel 的多路复用; 借助于select监听,channel阻塞在select ,
二、使用场景
- 协程间通信,即协程间数据传输;
- 并发场景下利用channel的阻塞机制,作为同步机制(类似队列);例如并发打印日志,可以把并发写日志请求写入channel,然后使用另个一协程在读取channel 中请求,写日志。
- 利用channel关闭时发送广播的特性,作为协程退出通知;channel 关闭的时候,会向所有监听它的协程发送一个零值。
三、例子
1.包
代码如下(示例):case/channel.go
package _case import ( "fmt" "time" ) // 协程间通信 func Communication() { // 定义一个可读可写的通道 ch := make(chan int, 0) go communicationF1(ch) go communicationF2(ch) } // F1接受一个只写通道 func communicationF1(ch chan<- int) { // 通过循环向通道写入0~99 for i := 0; i < 99; i++ { ch <- i } } // F1接受一个只读通道 func communicationF2(ch <-chan int) { // 通过循环向通道写入0~99 for 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 := 0 for { 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 main import ( _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 用于
协程间通讯,必须存在读写双方,否则将造成死锁
。