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,无论收发都会被阻塞
相关推荐
Lhan.zzZ5 小时前
QML 组件库:VS2022 + Qt 静态库方案
开发语言·c++·qt·visual studio
敲代码的嘎仔5 小时前
28届后端开发-海康威视日常实习一面(已OC)
java·开发语言·后端·面试·海康威视·实习·大厂
sakiko_7 小时前
OC基础语法(与Swift对比)-1
开发语言·ios·objective-c·swift
迷迭香yy7 小时前
基金档案数据工程实战从收入分析到持仓穿透的Python解析 IG50免费开源股票数据API接口
开发语言·python
晊晌_h8 小时前
嵌入式从0到精通——线程
java·开发语言·jvm
一木 之林8 小时前
五、C++ 新特性、关键字与编译原理(进阶)(二)
java·开发语言·c++
OPEN-F8 小时前
C++11/14新特性精讲:移动语义与智能指针实战
开发语言·c++·算法
小灰灰搞电子8 小时前
Rust+Slint 实现动态轮播图源码分享,支持动态删除、添加
开发语言·rust·slint·动态轮播图
前端 贾公子8 小时前
第09章:上下文与记忆 (6)
开发语言·前端·python
sunburn-8 小时前
Java堆(Heap)详解与实战教学
java·开发语言·数据结构·ide·算法