• Go语言管道


    Channel概念

    Channel 是Go中的一个核心类型,你可以把它看成一个管道Channel是引用类型,操作符是箭头 <- 

    Channel 是 CSP 模式的具体实现,用于多个 goroutine 通讯。其内部实现了同步,确保并发安全。

    Channel 是线程安全的先进先出,多个goroutine同时访问,不需要加锁,channel是有类型的,一个整数的channel只能存放整数。

    Channel定义

    第一种,channel声明

    声明int类型的chan

    var ch chan int

    声明string类型的chan

    var ch chan string

    声明map类型chan

    var ch chan map[int]string

    第二种,使用make定义,无缓冲channel

    var ch1 chan int = make(chan int)
    var ch2 = make(chan int)
    ch3 := make(chan int)

    第三种,使用make定义,有缓冲channel

    var ch1 chan int = make(chan int, 10)
    var ch2 = make(chan int, 10)
    ch3 := make(chan int, 10)

    第四种,只读channel

    var ch1 <-chan int
    var ch2 <-chan int = make(<-chan int, 10)
    var ch3 = make(<-chan int, 10)
    ch4 := make(<-chan int, 10)

    第五种,只写channel

    var ch1 chan<- int
    var ch2 chan<- int = make(chan<- int, 10)
    var ch3 = make(chan<- int, 10)
    ch4 := make(chan<- int, 10)

    Channel特点

    无缓冲的与有缓冲channel有着重大差别,那就是一个是同步的 一个是非同步的。

    比如

    无缓冲chan:ch1:=make(chan int)

    有缓冲chan:ch2:=make(chan int,1)

    无缓冲: ch1<-1 不仅仅是向 c1 通道放 1,而是一直要等有别的携程 <-ch1 接手了这个参数,那么ch1<-1才会继续下去,要不然就一直阻塞着。

    有缓冲: ch2<-1 则不会阻塞,因为缓冲大小是1(其实是缓冲大小为0),只有当放第二个值的时候,第一个还没被人拿走,这时候才会阻塞。

    缓冲区是内部属性,并非类型构成要素。

    普通 channel 可以隐式转为只读channel或只写channel。

    package main
    
    var ch = make(chan int, 3)
    var send chan<- int = ch
    var recv <-chan int = ch
    
    func main() {
    
    }

    只读channel或只写channel不能转为普通 channel。

    package main
    
    func main() {
        var send chan<- int
        var recv <-chan int
    
        ch1 := (chan int)(send)
        ch2 := (chan int)(recv)
    }

    编译错误:

    ./main.go:7:19: cannot convert send (type chan<- int) to type chan int
    ./main.go:8:19: cannot convert recv (type <-chan int) to type chan int

    Channel操作

    使用内置函数 len() 返回未被读取的缓冲元素数量,使用内置函数 cap() 返回缓冲区大小。

    package main
    
    import "fmt"
    
    func main() {
        ch1 := make(chan int)
        ch2 := make(chan int, 3)
    
        ch2 <- 1
    
        fmt.Printf("ch1 缓冲元素数量:%v,缓冲区大小:%v
    ", len(ch1), cap(ch1))
        fmt.Printf("ch2 缓冲元素数量:%v,缓冲区大小:%v
    ", len(ch2), cap(ch2))
    }

    运行结果:

    ch1 缓冲元素数量:0,缓冲区大小:0
    ch2 缓冲元素数量:1,缓冲区大小:3

    channel 写入、读取操作:

    package main
    
    import "fmt"
    
    func main() {
        ch := make(chan int, 1)
        // 写入chan
        ch <- 99
    
        // 读取chan
        value, ok := <-ch
        if ok {
            fmt.Printf("读取chan:%v
    ", value)
        }
    
    }

    channel 关闭操作

    1、使用内置函数 close() 进行关闭 chan。
    2、chan关闭之后,for range遍历chan中已经存在的元素后结束。
    3、没有使用for range的写法需要使用,val, ok := <- ch进行判断chan是否关闭。

    package main
    
    import "fmt"
    
    func main() {
        ch := make(chan int, 5)
    
        ch <- 1
        ch <- 2
        ch <- 3
    
        close(ch)
        for {
            val, ok := <-ch
            if ok == false {
                fmt.Println("chan is closed")
                break
            }
            fmt.Println(val)
        }

    注意:向已经关闭的 channel 发送数据会引发 panic 错误。

    package main
    
    func main() {
        ch := make(chan int, 1)
        close(ch)
        ch <- 100
    }

    运行错误:

    panic: send on closed channel
  • 相关阅读:
    音乐分类/生成杂记
    音视频编码笔记
    《The challenge of realistic music generation: modelling raw audio at scale》论文阅读笔记
    使用基于Caffe的MobileNet分类踩坑备忘录
    四大轻量化模型对比(转)
    WaveNet: 原始音频生成模型
    《SONG FROM PI: A MUSICALLY PLAUSIBLE NETWORK FOR POP MUSIC GENERATION》论文笔记
    上采样 及 Sub-pixel Convolution (子像素卷积)
    python之sys._getframe() 用于查看函数被什么函数调用以及被第几行调用及被调用函数所在文件
    11
  • 原文地址:https://www.cnblogs.com/jiangchunsheng/p/10753371.html
Copyright © 2020-2023  润新知