浅谈golang通道类型

 更新时间:2023年02月14日 11:06:36   作者:飞马攻城师  
本文主要介绍了浅谈golang通道类型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、什么是通道类型

Go 语言中的通道(channel)是一种特殊的类型。通道像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型。

如果说goroutine是Go程序并发的执行体,channel就是它们之间的连接。channel是可以让一个goroutine发送特定值到另一个goroutine的通信机制。

二、通道产生的原因

虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题。为了保证数据交换的正确性,必须使用互斥量对内存进行加锁,这种做法势必造成性能问题。

Go语言的并发模型是CSP(Communicating Sequential Processes),提倡通过通信共享内存而不是通过共享内存而实现通信。

三、声明channel

语法:

var 变量 chan 元素类型  

例:

var ch1 chan int   // 声明一个传递整型的通道
var ch2 chan bool  // 声明一个传递布尔型的通道
var ch3 chan []int // 声明一个传递int切片的通道   

四、创建channel

语法:

make(chan 元素类型, [缓冲大小])  

注意: 声明的通道后需要使用make函数初始化之后才能使用。channel的缓冲大小是可选的。

例:

ch4 := make(chan int, 3)
ch5 := make(chan bool)
ch6 := make(chan []int)   

五、channel相关操作

1、发送值

将一个值发送到通道中。

例:

ch <- 10 // 把10发送到ch中   

2、接收值

从一个通道中接收值。

例:

x := <- ch // 从ch中接收值并赋值给变量x
<-ch       // 从ch中接收值,忽略结果   

3、关闭通道

例:

close(ch)   

3.1 注意

只有在通知接收方goroutine所有的数据都发送完毕的时候才需要关闭通道。通道是可以被垃圾回收机制回收的,它和关闭文件是不一样的,在结束操作之后关闭文件是必须要做的,但关闭通道不是必须的。

3.2 特点

  • 对一个关闭的通道再发送值就会导致panic。
  • 对一个关闭的通道进行接收会一直获取值直到通道为空。
  • 对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值。
  • 关闭一个已经关闭的通道会导致panic。

六、通道类型

1、无缓冲通道

无缓冲的通道只有在有人接收值的时候才能发送值。就像你住的小区没有快递柜和代收点,快递员给你打电话必须要把这个物品送到你的手中,简单来说就是无缓冲的通道必须有接收才能发送。

语法:

ch := make(chan type) 

例:

func recv(c chan int) {
    ret := <-c
    fmt.Println("接收成功", ret)
}
func main() {
    ch := make(chan int)
    go recv(ch) // 启用goroutine从通道接收值
    ch <- 10
    fmt.Println("发送成功")
}  

分析: 无缓冲通道上的发送操作会阻塞,直到另一个goroutine在该通道上执行接收操作,这时值才能发送成功,两个goroutine将继续执行。相反,如果接收操作先执行,接收方的goroutine将阻塞,直到另一个goroutine在该通道上发送一个值。

2、有缓冲通道

只要通道的容量大于零,那么该通道就是有缓冲的通道,通道的容量表示通道中能存放元素的数量。就像你小区的快递柜只有那么个多格子,格子满了就装不下了,就阻塞了,等到别人取走一个快递员就能往里面放一个。

语法:

ch := make(chan type, [cap]) 

例:

func main() {
    ch := make(chan int, 1) // 创建一个容量为1的有缓冲区通道
    ch <- 10
    fmt.Println("发送成功")
}   

七、单向通道

有的时候我们会将通道作为参数在多个任务函数间传递,很多时候我们在不同的任务函数中使用通道都会对其进行限制,比如限制通道在函数中只能发送或只能接收。

语法:

chan<- int  是一个只能发送的通道,可以发送但是不能接收;
<-chan int  是一个只能接收的通道,可以接收但是不能发送。

例:

func counter(out chan<- int) {
    for i := 0; i < 100; i++ {
        out <- i
    }
    close(out)
}

func squarer(out chan<- int, in <-chan int) {
    for i := range in {
        out <- i * i
    }
    close(out)
}
func printer(in <-chan int) {
    for i := range in {
        fmt.Println(i)
    }
}

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go counter(ch1)
    go squarer(ch2, ch1)
    printer(ch2)
}

注意: 在函数传参及任何赋值操作中将双向通道转换为单向通道是可以的,但反过来是不可以的。

八、从通道循环取值

例:

// channel 练习
func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    // 开启goroutine将0~100的数发送到ch1中
    go func() {
        for i := 0; i < 100; i++ {
            ch1 <- i
        }
        close(ch1)
    }()
    // 开启goroutine从ch1中接收值,并将该值的平方发送到ch2中
    go func() {
        for {
            i, ok := <-ch1 // 通道关闭后再取值ok=false
            if !ok {
                break
            }
            ch2 <- i * i
        }
        close(ch2)
    }()
    // 在主goroutine中从ch2中接收值打印
    for i := range ch2 { // 通道关闭后会退出for range循环
        fmt.Println(i)
    }
}   

分析: 有两种方式在接收值的时候判断通道是否被关闭,我们通常使用的是for range的方式。

到此这篇关于浅谈golang通道类型的文章就介绍到这了,更多相关golang 通道类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言内建函数cap的实现示例

    Go语言内建函数cap的实现示例

    cap 是一个常用的内建函数,它用于获取某些数据结构的容量,本文主要介绍了Go语言内建函数cap的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2024-08-08
  • Go 实现 Nginx 加权轮询算法的方法步骤

    Go 实现 Nginx 加权轮询算法的方法步骤

    本文主要介绍了Go 实现 Nginx 加权轮询算法的方法步骤,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • 浅析Golang中闭包的创建与使用

    浅析Golang中闭包的创建与使用

    闭包是包括 Go 在内的编程语言的一项强大功能,通过闭包,您可以在函数中封装数据,并通过函数的返回值访问这些数据,本文将介绍Go 中闭包的基础知识,希望对大家有所帮助
    2023-11-11
  • Go并发编程之goroutine使用正确方法

    Go并发编程之goroutine使用正确方法

    并发编程有一种常见方式就是许多工作子协程都是独立的,互不干扰,但他们又是“同一时间”处理。本文重大给大家介绍Go并发编程goroutine使用方法,一起看看吧
    2021-09-09
  • Go语言带缓冲的通道的使用

    Go语言带缓冲的通道的使用

    Go语言中有缓冲的通道是一种在被接收前能存储一个或者多个值的通道,本文就来介绍一下Go语言带缓冲的通道的使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • Go并发调用的超时处理的方法

    Go并发调用的超时处理的方法

    这篇文章主要介绍了Go并发调用的超时处理的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • golang使用go mod导入本地包和第三方包的方式

    golang使用go mod导入本地包和第三方包的方式

    这篇文章主要介绍了golang使用go mod导入本地包和第三方包的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Golang观察者模式优化订单处理系统实例探究

    Golang观察者模式优化订单处理系统实例探究

    当涉及到订单处理系统时,观察者设计模式可以用于实现订单状态的变化和通知,在这篇文章中,我们将介绍如何使用Golang来实现观察者设计模式,并提供一个基于订单处理系统的代码示例
    2024-01-01
  • 使用Go语言生成二维码并在命令行中输出

    使用Go语言生成二维码并在命令行中输出

    二维码(QR code)是一种矩阵条码的标准,广泛应用于商业、移动支付和数据存储等领域,在开发过程中,我们可能需要在命令行中显示二维码,这可以帮助我们快速生成和分享二维码信息,本文将介绍如何使用Go语言生成二维码并在命令行中输出,需要的朋友可以参考下
    2023-11-11
  • 一文带你搞明白Go中的面向对象

    一文带你搞明白Go中的面向对象

    这篇文章主要为大家详细介绍了Go语言中面向对象的相关知识,文中的示例代码讲解详细,对我们深入了解Go语言有一定的帮助,需要的可以参考一下
    2023-07-07

最新评论