当前位置: 首页 > news >正文

Go的管道——channel

CSP  -->不要以内存的方式来通信(要上锁),相反,要通过通信来共享内存channel 本身就是一个队列  先进先出channel 是引用类型  可以使用make初始化   make -- map、slice、channel
channel 写满的时候不能写,取空的时候不能取  很容易发生阻塞  很容易产生死锁
每个channel 只能放同一种类型
使用channel 收发操作都是在不同的goroutinuechannel无缓冲通道有缓冲通道
无缓冲通道
package mainimport ("fmt""time"
)func main() {//无缓冲通道 -->每次只能取一个ch1 := make(chan int)go senddata(ch1)time.Sleep(2 * time.Second)data := <-ch1fmt.Println("拿到通道数据:", data)data2 := <-ch1fmt.Println("拿到通道数据:", data2)//支持不同协程之间的通信// ch1 <- 3// data3 := <-ch1 //不行,会报错// fmt.Println("拿到通道数据:", data3)time.Sleep(2 * time.Second)
}func senddata(ch chan int) {ch <- 1fmt.Println("往通道里存放数据1")ch <- 2fmt.Println("往通道里存放数据2")
}
利用无缓冲通道 做协程的控制
package mainimport ("fmt""time"
)//利用无缓冲通道 做协程的控制
//主协程退出  子协程也会跟着退出。利用通道取控制主协程等待子协程执行完成再退出type signal struct{}func senddata(ch chan int) {fmt.Println("this is senddata...")time.Sleep(2 * time.Second)ch <- 1//子协程执行完了,就往通道里面放数据
}func main() {fmt.Println("this is main")ch1 := make(chan int)go senddata(ch1)fmt.Println("等待子协程执行完毕")<-ch1//从通道里拿到数据,才能继续执行,不然就处于阻塞状态fmt.Println("end...")
}
使用空结构体,更节省空间
package mainimport ("fmt""time"
)
//最好使用空结构体  模拟信号发生type signal struct{}func senddata(ch chan signal) {fmt.Println("this is senddata...")time.Sleep(2 * time.Second)ch <- signal{} //子协程执行完了,就往通道里面放数据
}func main() {fmt.Println("this is main")ch1 := make(chan signal)go senddata(ch1)fmt.Println("等待子协程执行完毕")<-ch1 //从通道里拿到数据,才能继续执行,不然就处于阻塞状态fmt.Println("end...")
}
通道的关闭——消费者不会因为没有数据产生死锁
package mainimport ("fmt""time"
)// 通道的关闭  生产者发送完毕数据,关闭通道。消费者就不会因为没有数据产生死锁
func senddata(ch chan string) {defer fmt.Println("数据发送完毕")for i := 0; i < 3; i++ {ch <- fmt.Sprintf("发送数据:%d", i)}//defer fmt.Println("数据发送完毕")defer close(ch) //关闭通道,拿取方判断通道是否关闭,避免产生死锁
}func main() {ch1 := make(chan string)go senddata(ch1)//方式一  判断通道是否关闭for {data := <-ch1//如果通道关闭,读取的就是数据类型的默认值if data == "" {break}fmt.Println("拿到的数据:", data)}//方式二for {data, ok := <-ch1//如果ok为false  表示通道关闭if !ok {break}fmt.Println("from channel:", data)}//方式三   range   --> string slice  map  channel//range 会自动判断通道是否关闭for value := range ch1 {fmt.Println("from channel:", value)}
}
有缓冲通道
package mainimport ("fmt""time"
)// 有缓冲通道
func main() {ch1 := make(chan string, 6)go senddata(ch1)time.Sleep(2 * time.Second)for data := range ch1 {fmt.Println("读取通道数据:", data)}
}func senddata(ch chan string) {for i := 0; i < 10; i++ {ch <- fmt.Sprintf("data: %d", i)fmt.Println("往通道里放数据:", i)}defer close(ch)
}
监听通道
//select  监听通道
/*
select 同时监听多个通道操作,实现非阻塞通信和多路复用,实现高效的并发处理
select 语句监听多个通道操作,并且执行第一个准备好的操作,如果多个同时准备好,随机挑选一个执行如果没有通道准备好,select语句一直阻塞,直到至少有一个通道操作准备好
*/package mainimport ("fmt""time"
)func main() {ch1 := make(chan int)ch2 := make(chan int)ch3 := make(chan int)go func() {time.Sleep(10 * time.Second)ch1 <- 1}()go func() {time.Sleep(1 * time.Second)ch2 <- 2}()go func() {time.Sleep(3 * time.Second)ch3 <- 3}()for i := 0; i < 3; i++ {select {case msg := <-ch1:fmt.Println("接收到数据from ch1:", msg)case msg := <-ch2:fmt.Println("接收到数据from ch2:", msg)case msg := <-ch3:fmt.Println("接收到数据from ch3:", msg)case <-time.After(1 * time.Second):fmt.Println("设置超时时间,timeout!")// default://  fmt.Println("没有消息准备好!")}}
}
http://www.dtcms.com/a/299984.html

相关文章:

  • HTML5元素相关补充
  • HighlightingSystem
  • MATLAB近红外光谱分析技术及实践技术应用
  • C++ 类型萃取:深入理解与实践
  • 【AcWing 143题解】最大异或对
  • Android-广播详解
  • 零拷贝应用场景
  • 【Spring AI】大模型服务平台-阿里云百炼
  • 基于cooragent的旅游多智能体的MCP组件安装与其开发
  • javaSE 6
  • connect系统调用及示例
  • Go-Elasticsearch v9 安装与版本兼容性
  • Docker常用命令详解:以Nginx为例
  • 求hom_math_2d的角度值
  • Aerospike架构深度解析:打造web级分布式应用的理想数据库
  • JS实现数字变化时,上下翻滚动画效果
  • 本地部署智能家居集成解决方案 ESPHome 并实现外部访问
  • 五分钟系列-文本搜索工具grep
  • 【工具】好用的浏览器AI助手
  • 【MySQL】VARCHAR(10) 和 VARCHAR(100) 的区别
  • 大模型蒸馏(distillation)---从DeepseekR1-1.5B到Qwen-2.5-1.5B蒸馏
  • 拒绝SQL恐惧:用Python+pyqt打造任意Excel数据库查询系统
  • C++ - 仿 RabbitMQ 实现消息队列--服务端核心模块实现(四)
  • 丝杆升降机应用在食品机械行业有什么特殊的要求吗
  • Java BeanUtils 类详解:作用、语法与示例
  • springboot 基于签名的安全通信
  • 深入解析YARN中的FairScheduler与CapacityScheduler:资源分配策略的核心区别
  • Aerospike Java客户端进阶:对象映射与Spring Data集成实战
  • spring Could 高频面试题
  • 【科普】java和html和lvgl生成页面有什么区别,还有什么方法可以生成?