go语言中的Channel

文章目录

Channel

概述

​ channel是Go语言中的一个核心类型,可以把它看成管道(pipe)并不完全相同。并发核心单元通过它就可以发送或者接收数据进行通讯

channel是一个数据类型,主要用来解决go程的同步问题以及go程之间数据共享(数据传递)的问题。

goroutine运行在相同的地址空间,因此访问共享内存必须做好同步。goroutine 奉行通过通信来共享内存,而不是共享内存来通信。

引⽤类型 channel可用于多个 goroutine 通讯。其内部实现了同步,确保并发安全。

定义channel变量

和map、切片一样,需要先使用make申请空间

无缓冲channel

  • 只有在读端和写端同时工作时,才不会发生阻塞
  • 无缓冲取的管道长度是1,读端和写端要同时就绪才能通信

创建格式

go 复制代码
 make(chan Type)
go 复制代码
//写管道
func WriteChannel(pipe chan int){
    i := 1
    for { 
        pipe <- i
        i++
    }
}
//读管道
func ReadChannel(pipe chan int){
    defer fmt.Println("读管道协程结束")
    for	{
        //打印管道中的数据
        fmt.Println("管道中读取的数据 ",<-pipe)
        time.Sleep(time.Second *1)	//休眠1s
    }
}
func main(){
    //无缓冲管道
    c := make(chan int)
    go WriteChannel(c)
    go ReadChannel(c)
    for{
        //垃圾回收
        runtime.GC()
    }
}

有缓冲channel

  • 如果管道中的数据被读取完毕后,写端不在写入,读端会阻塞
  • 如果管道写满,并且读端关闭,写端就会阻塞

创建格式

go 复制代码
 make(chan Type, capacity)

示例:

go 复制代码
func WriteChannel_1(pipe chan int){
    defer fmt.Println("写管道协程结束")
    for i:= 0; i <5; i++{
        pipe<-i
    }
}

//写管道
func WriteChannel(pipe chan int){
    i := 1
    for { 
        pipe <- i
        i++
    }
}
//读管道
func ReadChannel(pipe chan int){
    defer fmt.Println("读管道协程结束")
    for	{
        //打印管道中的数据
        fmt.Println("管道中读取的数据 ",<-pipe)
        time.Sleep(time.Second *1)	//休眠1s
    }
}
func main(){
    var c = make(chan int, 5)
    go WriteChannel(c)
    go ReadChannel(c)
    for{
        //垃圾回收
        runtime.GC()
    }
}

相关操作

  • 获取channel中剩余元素 len(ch)

  • 获取缓冲区元素容量大小 len(ch)

go 复制代码
func main(){
    
    c := make(chan int,5)
   // func(){}() 匿名函数
    
    go func(){
        i := 0
        c<-i
        fmt.Printf("len(c)=%d, cap(c)=%d\n", len(c), cap(c))
        
    }()
    
    
}

使用 range 来迭代不断操作channel:

go 复制代码
func main(){
    c := make(chan int)
    go func(){
        for i := 0; i < 5; i++{
			f<-i
            close(c)
        }
    }()
    
    for data := range c{
        fmt.Println(data)
    }
    fmt.Println("Finished")
}

关闭channel

close©

go 复制代码
func IsChannel(pipe chan int){
    //使用断言判断,true说明管道没被关闭
    if data,ok := <-c;ok{
        fmt.Println(data)
    }else{
        break;
	}
}

func WriteChannel(pipe chan int){
    i := 0;
    for	{
        pipe<-i
        i++
        
        if(i == 5){
            close(pipe) //关闭管道 只是当前以及当前下的Goroutine协程不能使用了,不在使用,其他协程还是可以使用的
            runtime.GoExot();
        }
    }
}
func main(){
    var c = make(chan int,5)
    go WriteChannel(c)
    for{}
}

单向channel

单向channel 一般都是在参数中使用的

可以将 channel 隐式转换为单向队列,只收或只发,不能将单向 channel 转换为普通

  • 只写cahnnel 格式 chan<-

  • 只读channel 格式 <- chan

go 复制代码
//只写channel
func WriteChannel(pipe chan<- int){
    for i := 1; i <5; i++{
     	pipe<-i;
        i++;
    }
}
//只读channel
func ReadChannel(pipe <-channel int){
    for data := range pipe{
        fmt.Println(data)
    }
}
func main(){
    c := make(chan int,5)
    go WriteChannel(c)
    go ReadChannel(c)
    for{
        runtime.GC();
    }
}

总结

  • channel不像文件一样需要经常去关闭,只有当你确实没有任何发送数据了,或者是想显式的结束range循环之类的,才去关闭channel;
  • 关闭channel后,无法向channel 再发送数据(引发 panic 错误后导致接收立即返回零值);
  • 关闭channel后,可以继续从channel接收数据;
  • 对于nil channel,无论收发都会被阻塞
相关推荐
Frank_refuel几秒前
【C++项目】手撕JRpc框架(单机怎么优化到分布式思想)
开发语言·c++
可乐鸡翅yeah_18 分钟前
fmp4 碎片 MP4 格式 HLS 流,和传统 TS 分片有什么不一样
开发语言·javascript·ios·音视频·safari·m3u8·m3u8在线播放
流形填表21 分钟前
多校区题库标准化:Excel模板与校验脚本
开发语言·python
步行cgn30 分钟前
AOP 通知的类型详解
开发语言
weixin_3077791332 分钟前
从“人操作仪器”到“Agent 自主发现”:OPL 金属材料自驱动实验室 MVP 技术论述
开发语言·人工智能·算法·架构
笑鸿的学习笔记1 小时前
C++笔记之SIMD与SSE指令集
开发语言·c++·笔记
福兮说1 小时前
URL 编码的七个坑:c++ 传到后端变空格、%25 套娃、截断 emoji 直接报错
开发语言·前端·javascript·node.js·url
小的时候可菜了2 小时前
JS 异步的本质:从单线程到 thenable(一条进化链)
开发语言·前端·javascript
可乐鸡翅yeah_2 小时前
hls.js 配置 loadStartPosition,点播起始播放位置踩坑
开发语言·javascript·网络协议·ecmascript·m3u8在线
JWASX2 小时前
Java 转 go 学习 - 函数(1)
学习·golang