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,无论收发都会被阻塞
相关推荐
LDR00612 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术12 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript
码云数智-园园12 天前
C++20 Modules 模块详解
java·开发语言·spring
swordbob12 天前
NIO的channel中什么是 fd(File Descriptor,文件描述符)
java·开发语言·nio
源分享12 天前
Java线程同步的多种实现方法(非常详细)
java·开发语言·jvm
Luminous.12 天前
C语言--day30
c语言·开发语言
何以解忧,唯有..12 天前
Go语言循环语句详解:for、range与循环控制
开发语言·算法·golang
謓泽12 天前
C语言不是语法,是通往机器的地图。
c语言·开发语言
云水一下12 天前
从零开始学 PHP 系列(一):PHP 的前世今生与开发环境搭建
开发语言·php
飞天狗11112 天前
零基础JavaWeb入门——第五课第二小节:九大内置对象 · 第2个:response(响应对象)
java·开发语言