您现在的位置是:首页 >其他 >Go-channel的妙用网站首页其他
Go-channel的妙用
简介Go-channel的妙用
系列文章目录
异常处理(defer recover panic)
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 用于
协程间通讯,必须存在读写双方,否则将造成死锁
。
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。