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,无论收发都会被阻塞
相关推荐
我是唐青枫4 小时前
C#.NET YARP 跨域配置详解:网关统一处理 CORS
开发语言·c#·.net
风流 少年4 小时前
Python数据类型:类class、反射dataclasses、functools、typing、pydantic
开发语言·windows·python
lzhdim4 小时前
C#性能优化技巧
开发语言·性能优化·c#
森G4 小时前
TypeScript环境搭建---------------基于windows10
开发语言·typescript
wand codemonkey4 小时前
(三十)web应用+【核心】+【规矩】+【原理】
java·开发语言·前端
阿正的梦工坊4 小时前
Kotlin:现代编程语言的优雅之选
android·开发语言·kotlin
threelab4 小时前
潮玩DIY设计平台技术解析:基于Babylon.js的3D定制化实践
开发语言·javascript·3d
郝学胜-神的一滴4 小时前
Qt 高级开发 007: 图片查看器案例
开发语言·c++·qt·程序人生·开源软件
lfw20194 小时前
HSmartWindowControlWPF 和HWindowControlWPF的区别
开发语言·javascript·ecmascript