无缓冲的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,否则在我们在循环的时候会进入死锁状态

  1. 通过 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)
}
  1. 通过 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协程还没有机会执行,下面是几种等待协程结束的方案

  1. 利用 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()
}
  1. 利用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等待的几种情形

场景:比如我们现在要做十个前端任务和十个后端任务,我们有以下需求

  1. 我们希望前端任务顺序执行,后端任务顺序执行
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}
}

执行结果如下

  1. 我们希望前端任务先全部做完,然后后端任务全部做完,然后继续做别的事情
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}
}

执行结果如下

  1. 我们希望前端任务和后端任务交替并发执行
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详解相关推荐

  1. Go Channel 详解

    原文链接:Go Channel 详解 Channel类型 Channel类型的定义格式如下: ChannelType = ( "chan" | "chan" & ...

  2. netty系列之:netty中的Channel详解

    文章目录 简介 Channel详解 异步IO和ChannelFuture Channel的层级结构 释放资源 事件处理 总结 简介 Channel是连接ByteBuf和Event的桥梁,netty中的 ...

  3. Netty网络编程(三):Channel详解

    文章目录 简介 Channel详解 异步IO和ChannelFuture Channel的层级结构 释放资源 事件处理 总结 简介 Channel是连接ByteBuf和Event的桥梁,netty中的 ...

  4. netty系列之:netty中各不同种类的channel详解

    文章目录 简介 ServerChannel和它的类型 Epoll和Kqueue AbstractServerChannel ServerSocketChannel ServerDomainSocket ...

  5. Java网络编程(6)NIO - Channel详解

    前言 NIO的三个核心组件:Buffer.Channel.Selector Java网络编程(4)NIO的理解与NIO的三个组件完成了大概的了解 Java网络编程(5)NIO - Buffer详解详细 ...

  6. Channel详解 通信基础入门(详细讲解通俗易懂)

    在标准的IO当中,都是基于字节流/字符流进行操作的,而在NIO中则是是基于Channel和Buffer进行操作,其中的Channel的虽然模拟了流的概念,实则大不相同. 区别 Stream Chann ...

  7. NIO详解(九):Channel详解

    1. Channel概述 Java NIO的通道类似流,但又有些不同. Channel既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. Channel通道可以异步地读写. Chan ...

  8. go语言之行--golang核武器goroutine调度原理、channel详解

    一.goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心.goroutine使用方式非常的简单,只需使用go关键字 ...

  9. Java NIO学习篇之通道Channel详解

    定义: Channel:通道,运输的介质,可以大致比喻成铁路的铁轨,连接着两个车站,而channel用于打开与IO设备的连接,比如磁盘,套接字等. 通道使用完需要关闭. 与传统IO的Stream比较: ...

  10. NIO中的Channel详解

    NIO的通道类似于流,但有些区别如下: •通道可以同时进行读写,而流只能读或者只能写 •通道可以实现异步读写数据 •通道可以从缓冲区(Buffer)读数据,也可以写数据到缓冲区 BIO 中的 stre ...

最新文章

  1. jQuery_第五章_jQuery事件和动画
  2. WPF Snoop 2.7 源码研究
  3. html测试大题代码,Html5+js测试题(示例代码)
  4. 抑制恐慌,互联网能够做些什么?
  5. Datatable Initialization - 使用objects数据源初始化
  6. Java 8类型注释
  7. 近期计算机视觉算法竞赛汇总—总奖池超300万人民币
  8. 利用脚本启动java程序
  9. 什么是php 的精华,PHP精华
  10. activiti工作流 php,码云社 | 砺锋科技-SpringBoot整合Activiti工作流(附源码) - 用代码改变世界...
  11. 成语小秀才小程序源码-小程序前端-小程序吸粉引流源码
  12. 跟我做一个可以聊天的 Visual Studio Code 插件
  13. signature=45f2913b66c5b2ae668a6622be005d65,国开大《商务英语4》自测试题及答案
  14. 开发者必看|Android 8.0 新特性及开发指南
  15. Arduino基础入门篇12—火焰报警器
  16. DELLEMC S4048
  17. 小学老师工资多少一个月_当农村小学教师工资一年有多少,我给你们看一看
  18. 《预训练周刊》第26期:有效扩展:来自预训练和微调变换器的见解、rct.ai训练出5亿参数的BERT-X模型...
  19. AR眼镜语音转文字实测!效果像开了弹幕,对话记录可保存回溯
  20. php图书馆管理系统的设计与实现毕业设计-附源码

热门文章

  1. 如何成为数据分析师?小白这样做,快速入门数据分析
  2. 女生什么样的表现会说明她喜欢你?——男生记得都看一遍,谨记~
  3. C++萌新来看,一篇文让你让你彻底搞定类(超详细)!
  4. rust腐蚀怎么建立单机服务器_腐蚀rust搭建Rust服务器及联机教程
  5. 浏览器 本地html 图片不显示图片,网页图片显示不出来几种常见的解决方案
  6. 电容与电感串联直流电路系统分析
  7. matlab中普通电感,matlab电感在哪
  8. 双硬盘双win10互不干扰_双硬盘装WIN7 WIN10双系统
  9. 什么是NFV?什么是SDN?他与SDN的区别是什么
  10. java 汉字转拼音_java汉字转拼音