c语言编程笔录

首页 >   > 笔记大全

笔记大全

golang channel用法

更新时间:2023-07-09

什么是 golang channel

Go语言的channel是一种独特的数据结构,在实现并发的时候非常重要。channel是Go语言通信的核心,它也是Go语言的独特之处之一。一般来说,channel可以理解为一个通道,通过它可以实现不同协程之间的通信和同步。

package main

import "fmt"

func main() {
    // 创建一个通道
    ch := make(chan int)

    // 向通道发送值
    ch <- 10

    // 从通道接收值
    num := <-ch

    fmt.Println(num)
}

上面的代码展示了如何使用make创建一个channel,然后向通道发送值,最后从通道中接收值。这里需要注意的是,向通道发送值和从通道接收值都是需要采用`<-`操作符的。如果没有接收方,发送操作就会一直阻塞。

channel的阻塞与非阻塞

Go语言中的channel分为同步和异步两种方式,也就是阻塞和非阻塞。默认情况下,channel是同步方式:发送方发送数据后必须等到接收方接收完毕后才能继续发送。

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)

    // 同步方式
    go func() {
        ch <- 10
        fmt.Println("发送完毕")
    }()
    time.Sleep(2 * time.Second)

    num := <-ch
    fmt.Println(num)
}

上面的代码展示了一个同步方式的channel:发送方发送数据后,必须等待接收方接收完毕后才会打印“发送完毕”。在此期间,主协程一直处于阻塞状态。

如果想要使用异步方式的channel,可以采用非阻塞的方式。这时候,发送方可以直接向通道中发送数据,接收方可直接读取数据(不需要等待发送方完成)。

package main

import (
    "fmt"
)

func main() {
    ch := make(chan int, 1)

    // 异步方式
    go func() {
        ch <- 10
        fmt.Println("发送完毕")
    }()

    num := <-ch
    fmt.Println(num)
}

上面的代码展示了一个异步方式的channel:发送方向通道发送数据后,直接打印“发送完毕”,而接收方在自己准备好之后去读取数据即可,不需要等待。

channel 的方向

Go语言中的channel还可以指定方向,使得发送方只能向通道发送数据,而接收方只能从通道中读取数据。这样可以增强代码的安全性和可读性,防止出现不必要的错误。

package main

import "fmt"

func send(ch chan<- int, val int) {
    ch <- val
}

func receive(ch <-chan int) {
    fmt.Println(<-ch)
}

func main() {
    ch := make(chan int)

    go send(ch, 10)
    receive(ch)
}

上面的代码定义了两个函数send和receive: send函数只能用于向通道中发送数据(而不是接收数据),而receive函数只能用于从通道中接收数据(而不是发送数据)。如果尝试在send函数中读取数据,或在receive函数中发送数据,则编译器将会报错。

channel 关闭

Go语言中的channel还支持关闭操作,通过关闭无缓冲的channel来表示数据已经传送完成。一般来说,在发送方关闭channel之后,接收方将会收到非阻塞的零值。但是在通道中还有剩余元素的情况下,接收方还是可以继续接收完所有元素。

package main

import "fmt"

func main() {
    ch := make(chan int)

    go func() {
        for i := 0; i < 5; i++ {
            ch <- i
        }
        close(ch)
    }()

    for val := range ch {
        fmt.Println(val)
    }
}

上面的代码展示了在for-range循环中使用通道的方式。在发送方向通道中发送完5个数据后,发送方调用close函数,标志着数据已发送完毕。在主协程中,通过for-range循环遍历通道,并且如果通道已关闭则退出循环体。