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,无论收发都会被阻塞
相关推荐
quantdash_cc2 小时前
告别自建 Requests/BS4 网页爬虫:基于 QuantDash 搭建零维保的高性能量化行情流水线
开发语言·爬虫·python·pandas·量化·quantdash
ydd1001002 小时前
寻找两个正序数组的中位数 Java 题解,二分分割详解
java·开发语言
半亩码田2 小时前
C#转Python第3.1篇:Python 的 class 没有访问修饰符?面向对象的另一条路
开发语言·python·c#
Wzx1980123 小时前
python沙箱和docker沙箱你选对了吗?
开发语言·python·docker
牧羊人.3333 小时前
Python 办公自动化从入门到入土|09 数据容器之字典
开发语言·python
小僧景贤3 小时前
嵌入式C语言 第二篇:基础语法|嵌入式C与标准C的核心差异
c语言·开发语言·嵌入式c语言
阿pin4 小时前
Android随笔-AIDL
android·开发语言·aidl
LiLiYuan.4 小时前
【字符串常量池】
java·开发语言·面试
瑞码空间5 小时前
Python爬虫进阶实战笔记
开发语言·python·计算机·python爬虫
16月6日-晴5 小时前
Java面向对象进阶—static
java·开发语言