Go channel详解
无缓冲的channel
下面代码一定报错,因为没有接收的函数就一个劲儿往c channel中发送数据
package mainfunc main() {c := make(chan int) // make的第二个参数我们不传或者填写0,都会创建一个无缓冲的channel,此时必须声明一个go携程接收数据,否则一定会报错c <- 1c <- 2n := <-ctime.Sleep(time.Second)
}
// fatal error: all goroutines are asleep - deadlock!
一定要创建一个go携程先接收,然后才可以往无缓冲的channel里面发送数据
// 正确示范如下
package mainfunc main() {c := make(chan int)go func() {for {n := <-cfmt.Println(n)}}()c <- 1c <- 2time.Sleep(time.Second)
}
有缓冲的channel
package mainfunc main() {c := make(chan int, 3) // 创建可以一个缓冲区可以容纳三个int型的channelc <- 1c <- 2c <- 3//c <- 4 // 如果这里塞第四个值,而缓冲区大小我们设置的3的话,这里会报错fatal error: all goroutines are asleep - deadlock!fmt.Println(<-c)fmt.Println(<-c)fmt.Println(<-c)//fmt.Println(<-c) // 如果这里接收的值超过了channel的值,这里也会报死锁的错误,所以一定要注意缓冲区多大,就只能接受多大的值//fmt.Println(n)time.Sleep(time.Second)
}
如何判断channel是否已经接收完毕
注意无论有缓冲还是无缓冲的channel,channel数据发送完毕以后,一定要close
掉开辟的channel
,否则在我们在循环的时候会进入死锁状态
- 通过
range
接收数据
package mainfunc main() {c := make(chan int, 3)c <- 1c <- 2c <- 3close(c) // 此处如果不关闭会进入死锁状态,fatal error: all goroutines are asleep - deadlock!for v := range c {fmt.Println(v)}fmt.Println("数据已经接收完毕")time.Sleep(time.Second)
}
- 通过
v, ok := <-c
接收数据
package mainfunc main() {c := make(chan int, 3)c <- 1c <- 2c <- 3close(c) // 此处不close也会报错fatal error: all goroutines are asleep - deadlock!for {v, ok := <-cif !ok {break}fmt.Println(v)}time.Sleep(time.Second)
}
协程间通信
这里简要介绍一下几种协程间通讯的方式
等待协程结束
一般我们如果写开辟go协程的话,最好要在代码中time.Sleep(time.Second)
几秒,要不然main函数执行完毕的时候,go协程还没有机会执行,下面是几种等待协程结束的方案
- 利用 sync.WaitGroup 这个包来做
package mainimport ("fmt""sync"
)var wg sync.WaitGroupfunc main() {for i := 0; i < 10; i++ {wg.Add(1)go func(id int) {fmt.Println("current id is :", id)wg.Done()}(i)}wg.Wait()
}
- 利用channel等待
假设通过协程投递多个任务,想要等待所有任务执行结束以后让代码逻辑继续往下走,那么可以使用下面的方法,<-isComplete
这个方法会阻塞至所有任务完成然后继续向下顺序执行
package mainimport ("fmt""time"
)func main() {taskChannel := make(chan int, 10)// 任务是否已经结束isComplete := make(chan bool, 10)for i := 0; i < 10; i++ {go func(i int) {taskChannel <- i// TODO 假设做了很多事情time.Sleep(time.Second * 1)fmt.Println("当前任务id :", i, "已经完成掉了")isComplete <- true}(i)}for i := 0; i < 10; i++ {<-isComplete}fmt.Println("当前任务全部结束掉了")
}
channel等待的几种情形
场景:比如我们现在要做十个前端任务和十个后端任务,我们有以下需求
- 我们希望前端任务顺序执行,后端任务顺序执行
package mainimport "fmt"type task struct {data chan stringdone chan bool
}func (t task) Run() {for v := range t.data {fmt.Printf("current data = %s\n", v)t.done <- true}
}func createTask() task {task := task{data: make(chan string, 1),done: make(chan bool, 1),}go task.Run()return task
}func main() {var tasks [10]task// 创建任务出来,同时任务一直会消费数据for i := 0; i < 10; i++ {tasks[i] = createTask()}// 模拟塞进十个任务进去for i := 0; i < 10; i++ {data := fmt.Sprintf("前端任务【%d】", i)tasks[i].data <- data<-tasks[i].done}// 模拟塞进十个任务进去for i := 0; i < 10; i++ {data := fmt.Sprintf("后端任务【%d】", i)tasks[i].data <- data<-tasks[i].done}
}
执行结果如下
- 我们希望前端任务先全部做完,然后后端任务全部做完,然后继续做别的事情
package mainimport "fmt"type task struct {data chan stringdone chan bool
}func (t task) Run() {for v := range t.data {fmt.Printf("current data = %s\n", v)t.done <- true}
}func createTask() task {task := task{data: make(chan string, 1),done: make(chan bool, 1),}go task.Run()return task
}func main() {var tasks [10]task// 创建任务出来,同时任务一直会消费数据for i := 0; i < 10; i++ {tasks[i] = createTask()}// 模拟塞进十个任务进去for i := 0; i < 10; i++ {data := fmt.Sprintf("前端任务【%d】", i)tasks[i].data <- data}for i := 0; i < 10; i++ {<-tasks[i].done}// 模拟塞进十个任务进去for i := 0; i < 10; i++ {data := fmt.Sprintf("后端任务【%d】", i)tasks[i].data <- data}for i := 0; i < 10; i++ {<-tasks[i].done}
}
执行结果如下
- 我们希望前端任务和后端任务交替并发执行
package mainimport "fmt"type task struct {data chan stringdone chan bool
}func (t task) Run() {for v := range t.data {fmt.Printf("current data = %s\n", v)t.done <- true}
}func createTask() task {task := task{data: make(chan string, 1),done: make(chan bool, 1),}go task.Run()return task
}func main() {var tasks [10]task// 创建任务出来,同时任务一直会消费数据for i := 0; i < 10; i++ {tasks[i] = createTask()}// 模拟塞进十个任务进去for i := 0; i < 10; i++ {data := fmt.Sprintf("前端任务【%d】", i)tasks[i].data <- data}// 模拟塞进十个任务进去for i := 0; i < 10; i++ {data := fmt.Sprintf("后端任务【%d】", i)tasks[i].data <- data}for i := 0; i < 10; i++ {<-tasks[i].done<-tasks[i].done}
}
执行结果如下
Go channel详解相关推荐
- Go Channel 详解
原文链接:Go Channel 详解 Channel类型 Channel类型的定义格式如下: ChannelType = ( "chan" | "chan" & ...
- netty系列之:netty中的Channel详解
文章目录 简介 Channel详解 异步IO和ChannelFuture Channel的层级结构 释放资源 事件处理 总结 简介 Channel是连接ByteBuf和Event的桥梁,netty中的 ...
- Netty网络编程(三):Channel详解
文章目录 简介 Channel详解 异步IO和ChannelFuture Channel的层级结构 释放资源 事件处理 总结 简介 Channel是连接ByteBuf和Event的桥梁,netty中的 ...
- netty系列之:netty中各不同种类的channel详解
文章目录 简介 ServerChannel和它的类型 Epoll和Kqueue AbstractServerChannel ServerSocketChannel ServerDomainSocket ...
- Java网络编程(6)NIO - Channel详解
前言 NIO的三个核心组件:Buffer.Channel.Selector Java网络编程(4)NIO的理解与NIO的三个组件完成了大概的了解 Java网络编程(5)NIO - Buffer详解详细 ...
- Channel详解 通信基础入门(详细讲解通俗易懂)
在标准的IO当中,都是基于字节流/字符流进行操作的,而在NIO中则是是基于Channel和Buffer进行操作,其中的Channel的虽然模拟了流的概念,实则大不相同. 区别 Stream Chann ...
- NIO详解(九):Channel详解
1. Channel概述 Java NIO的通道类似流,但又有些不同. Channel既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. Channel通道可以异步地读写. Chan ...
- go语言之行--golang核武器goroutine调度原理、channel详解
一.goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心.goroutine使用方式非常的简单,只需使用go关键字 ...
- Java NIO学习篇之通道Channel详解
定义: Channel:通道,运输的介质,可以大致比喻成铁路的铁轨,连接着两个车站,而channel用于打开与IO设备的连接,比如磁盘,套接字等. 通道使用完需要关闭. 与传统IO的Stream比较: ...
- NIO中的Channel详解
NIO的通道类似于流,但有些区别如下: •通道可以同时进行读写,而流只能读或者只能写 •通道可以实现异步读写数据 •通道可以从缓冲区(Buffer)读数据,也可以写数据到缓冲区 BIO 中的 stre ...
最新文章
- jQuery_第五章_jQuery事件和动画
- WPF Snoop 2.7 源码研究
- html测试大题代码,Html5+js测试题(示例代码)
- 抑制恐慌,互联网能够做些什么?
- Datatable Initialization - 使用objects数据源初始化
- Java 8类型注释
- 近期计算机视觉算法竞赛汇总—总奖池超300万人民币
- 利用脚本启动java程序
- 什么是php 的精华,PHP精华
- activiti工作流 php,码云社 | 砺锋科技-SpringBoot整合Activiti工作流(附源码) - 用代码改变世界...
- 成语小秀才小程序源码-小程序前端-小程序吸粉引流源码
- 跟我做一个可以聊天的 Visual Studio Code 插件
- signature=45f2913b66c5b2ae668a6622be005d65,国开大《商务英语4》自测试题及答案
- 开发者必看|Android 8.0 新特性及开发指南
- Arduino基础入门篇12—火焰报警器
- DELLEMC S4048
- 小学老师工资多少一个月_当农村小学教师工资一年有多少,我给你们看一看
- 《预训练周刊》第26期:有效扩展:来自预训练和微调变换器的见解、rct.ai训练出5亿参数的BERT-X模型...
- AR眼镜语音转文字实测!效果像开了弹幕,对话记录可保存回溯
- php图书馆管理系统的设计与实现毕业设计-附源码
热门文章
- 如何成为数据分析师?小白这样做,快速入门数据分析
- 女生什么样的表现会说明她喜欢你?——男生记得都看一遍,谨记~
- C++萌新来看,一篇文让你让你彻底搞定类(超详细)!
- rust腐蚀怎么建立单机服务器_腐蚀rust搭建Rust服务器及联机教程
- 浏览器 本地html 图片不显示图片,网页图片显示不出来几种常见的解决方案
- 电容与电感串联直流电路系统分析
- matlab中普通电感,matlab电感在哪
- 双硬盘双win10互不干扰_双硬盘装WIN7 WIN10双系统
- 什么是NFV?什么是SDN?他与SDN的区别是什么
- java 汉字转拼音_java汉字转拼音