Golang中的channel

  • 为什么要使用channel
  • channel的介绍
  • channel的基本使用
    • 定义/声明channel
  • 管道的遍历和关闭
    • channel的关闭
    • channel的遍历
  • goroutine和channel结合
    • 应用实例1
    • 应用实例2
    • 案例
  • 注意事项

为什么要使用channel

前面使用全局变量加锁同步来解决goroutine的通讯,但不完美

  • 1.主线程在等待所有goroutine全部完成时间很难确定,我们这里设置10秒,仅仅是过段
  • 2.如果主线程休眠时间长了,会加长等待时间,如果等待时间短了,可能还有routine处于工作状态,这时也会随主线程的退出而销毁
  • 3.通过全局白能量加锁同步来实现通讯,也并不利用多个协程对全局变量的读写操作
  • 4.上面种种分析都在互换一个新的通讯机制-----channel

channel的介绍

  • 1.channel本质就是一个数据结构-队列
  • 2.数据是先进先出
  • 3.线程安全,多goroutine访问时,不需要加锁,就是说channel本身就是线程安全的
  • 4.channel是有类型的,一个string的channel只能存放string类型数据

channel的基本使用

定义/声明channel

var 变量名chan数据类型

举例:

var intChan chan int (intChan用于存放int数据)

var mapChan chan map[int]ssting (mapChan用于存放map[int]string类型)

var perChan chan Person

var perChan2 chan *Person

说明:

channel是引用类型

channel必须初始化才能写入数据,即make后才能使用

管道是有类型的,intChan只能写入整数

package mainimport "fmt"func main() {//演示一下管道的使用//创建一个可以存放三个int类型的俄管道var intChan chan intintChan = make(chan int, 3)//看看intChan是什么fmt.Printf("intChan的值=%v intChan本身的地址=%p\n", intChan, &intChan)//向管道写入数据intChan <- 10num := 211intChan <- num//看看管道的长度和cap(容量)fmt.Printf("channel len = %v cap=%v \n", len(intChan), cap(intChan))//从管道中读取数据var num2 intnum2 = <-intChanfmt.Println("num2=", num2)fmt.Printf("channel len =%v cap=%v \n", len(intChan), cap(intChan))//在没有使用协程的情况下,如果我们管道数据已经全部取出,在取就会报告deadlock
}
/*
intChan的值=0xc00010e080 intChan本身的地址=0xc000006028
channel len = 2 cap=3
num2= 10
channel len =1 cap=3
*/

管道的遍历和关闭

channel的关闭

使用内置函数close可以关闭channel,当channel关闭后,就不能再想channel写数据了,但是仍然可以从给channel读取数据

channel的遍历

channel支持for-range的方式进行遍历

1.在遍历时,如果channel没有关闭,则会出现deadlock的错误

2.在遍历时,如果channel已经关闭,则会出现正常遍历数据,遍历完后,就会退出遍历

package mainimport "fmt"func main() {intChan := make(chan int, 3)intChan <- 100intChan <- 200close(intChan)//这时不能够再写入到channel//intChan <- 300fmt.Println("okk")n1 := <-intChanfmt.Println("n1=", n1)//遍历管道intChan2 := make(chan int, 100)for i := 0; i < 100; i++ {intChan2 <- i * 2 //放入100个数据到管道}// 在遍历时,如果channel没有关闭,责护出现deadlock的错误close(intChan2)for v := range intChan2 {fmt.Println("v=", v)}}

goroutine和channel结合

应用实例1

package mainimport ("fmt""time"
)func writeData(intChan chan int) {for i := 1; i < 50; i++ {//放入数据intChan <- ifmt.Println("writeData", i)time.Sleep(time.Second)}close(intChan) //关闭
}//read data
func readData(intChan chan int, exitChan chan bool) {for {v, ok := <-intChanif !ok {break}time.Sleep(time.Second)fmt.Printf("readData读到数据=%v\n", v)}//readData读取完数据后,即任务完成exitChan <- trueclose(exitChan)
}func main() {//创建两个管道intChan := make(chan int, 50)exitChan := make(chan bool, 1)go writeData(intChan)go readData(intChan, exitChan)//time.Sleep(time.Second * 10)for {_, ok := <-exitChanif !ok {break}}
}

应用实例2

如果只是向管道写入数据,而没有读取,就会出现阻塞而dead lock,原因是intChan容量是10,而带点吗writeData会写入50个数据,因此就会阻塞在writeData的ch<-i

案例

package mainimport "fmt"func putNum(intChan chan int) {for i := 1; i <= 8000; i++ {intChan <- i}//关闭intChanclose(intChan)
}//开启四个协程,从intChan取出数据,并判断是否为素数
//如果是,就放入到primeChan
func primeNum(intChan chan int, primeChan chan int, exitChan chan bool) {//使用for循环var flag boolfor {num, ok := <-intChanif !ok {break}flag = true //假定是素数//判断num是不是素数for i := 2; i < num; i++ {if num%i == 0 { //说明该num不是素数flag = falsebreak}}if flag {//将这个数就放入到primeChanprimeChan <- num}}fmt.Println("有一个primeNum协程因为取不到数据,退出")//这里还不能关闭primeChan//向exitChan写入trueexitChan <- true
}func main() {intChan := make(chan int, 1000)primeChan := make(chan int, 2000) //放入结果//标识退出的管道exitChan := make(chan bool, 4)//开启一个协程,想in特产放入1-8000个数go putNum(intChan)//开启四个协程,从intChan取出数据,并判断是否为素数//如果是,就放入到primeChanfor i := 0; i < 4; i++ {go primeNum(intChan, primeChan, exitChan)}//这里进行主线程处理go func() {for i := 0; i < 4; i++ {<-exitChan}//当我们从exitChan,去出了4个结果,就可以放心关闭primeChanclose(primeChan)}()//遍历primeNum,把结果输出for {res, ok := <-primeChanif !ok {break}//将结果输出fmt.Printf("素数=%d\n", res)}fmt.Println("main线程退出")
}

注意事项

  • 1.channel可以声明为只读,或者只写性质
  • 2.channel只读和只写的最佳实践案例
package mainimport "fmt"func main() {//管道可以声明为只读或者只写//默认情况下,管道是双向的//var chan1 chan int//声明为只写var chan2 chan<- intchan2 = make(chan int, 3)chan2 <- 20//num := <-chan2fmt.Println("chan2=", chan2)//声明为只读var chan3 <-chan intnum2 := <-chan3fmt.Println("num2=", num2)
}
  • 3.使用select可以解决从管道取数据的阻塞问题
  • 4.goroutine中使用recover,解决携程中出现panic,导致程序奔溃问题
    • 说明,如果我们起了一个协程,但是这个协程出现了panic,如果我们没有捕获这个panic,就会造成整个程序崩溃,这是我们可以在goroutine中使用recover来捕获panic,进行处理,这样及时这个协程发生的问题,但是主线程仍然不受影响,

44-Golang中的channel相关推荐

  1. golang中并发sync和channel

    golang中并发sync和channel chenbaoke · 2014-12-08 13:00:01 · 19151 次点击 · 预计阅读时间 5 分钟 · 不到1分钟之前 开始浏览 这是一个创 ...

  2. golang 中 channel 的详细使用、使用注意事项及死锁分析

    什么是 channel 管道 它是一个数据管道,可以往里面写数据,从里面读数据. channel 是 goroutine 之间数据通信桥梁,而且是线程安全的. channel 遵循先进先出原则. 写入 ...

  3. golang中channel使用

    1 golang中channel使用 文章目录 1 golang中channel使用 1.1 channel介绍 1.2 channel使用 1.2.1 channel声明和初始化 1.2.2 cha ...

  4. golang中Channel通道(二)

    golang中Channel通道(二) 一.带缓冲和不带缓冲的通道的区别 1.非缓冲通道 一次发送操作对应一次接收操作,对于一个goroutine来讲,它的一次发送,在另一个goroutine接收之前 ...

  5. 如何在golang中关闭bufio.reader_Golang 并发模型系列:1. 轻松入门流水线模型

    Go语言中文网,致力于每日分享编码.开源等知识,欢迎关注我,会有意想不到的收获! Golang作为一个实用主义的编程语言,非常注重性能,在语言特性上天然支持并发,它有多种并发模型,通过流水线模型系列文 ...

  6. 进一步认识golang中的并发

    如果你成天与编程为伍,那么并发这个名词对你而言一定特别耳熟.需要并发的场景太多了,例如一个聊天程序,如果你想让这个聊天程序能够同时接收信息和发送信息,就一定会用到并发,无论那是什么样的并发. 并发的意 ...

  7. golang中的sync.WaitGroup

    golang中的sync.WaitGroup Posted on 2015/04/09刚才看golang的sync的包,看见一个很有用的功能.就是WaitGroup. 先说说WaitGroup的用途: ...

  8. 初步解读Golang中的接口相关编写方法

    初步解读Golang中的接口相关编写方法 概述如果说goroutine和channel是Go并发的两大基石,那么接口是Go语言编程中数据类型的关键.在Go语言的实际编程中,几乎所有的数据结构都围绕接口 ...

  9. golang中的nil

    golang中的nil与其他语言中的语义是一样的,就是代表引用类型的默认值,但是不一样的是, golang中有多种引用类型:pointer.interface.slice.map,channel, f ...

最新文章

  1. centos升级mysql到5.5
  2. redis集群环境安装(参照redis中文官网,中间遇到了一些问题,so,记录一下)
  3. 一个Web Project引用多个Java Project在Eclipse下的配置--转载
  4. 渗透测试 已学课时 1 个_我14岁上创业课时学到的东西
  5. Qt 自定义事件的实现
  6. java插入排序实现,经典(Java版)排序算法的分析及实现之一直接插入排序
  7. shiro-cas------实现单点登出并自定义登出starter
  8. 大话设计模式笔记(十二)の抽象工厂模式
  9. windows下安装sqlmap 详细教程
  10. 各种hadoop原理图
  11. iphone7p配置参数详情_求iPhone7具体参数配置
  12. java ltp4j_ltp工具使用配置
  13. 关于Bilibili下载问题
  14. 1034 有理数四则运算
  15. 通过下面语句创建employee数据库和dept(部门表)、emp(员工表)、salgrade(工资等级表)34题
  16. 数值计算之 最小二乘法(1)最小二乘计算与线性方程
  17. 原生JS利用XMLHttpRequest实现Get和Post请求
  18. 记录又一次实战GetShell
  19. 【白话机器学习系列】白话向量点积
  20. 系统分析与设计 作业1

热门文章

  1. 计算机各部件的作用是什么,计算机由哪些基本部件组成?各部件的作用是什么...
  2. 盒子的阴影:阴影的css格式
  3. 江南大学计算机安全概论,关于加强防范微软IE高危0day漏洞(CVE-2018-8653)的通知...
  4. 虚拟电厂:既不虚拟,也不发电,更不建厂
  5. dedecms免费转换yzncms
  6. 机器学习:推荐系统算法原理解析
  7. python middleware_Django框架之中间件MiddleWare的实现
  8. blob浏览器兼容问题解决
  9. [6]PCB设计实验|认识常用元器件|电阻器|18:30~19:00
  10. Java八股文面试,为什么会盛行?又该如何面对?