Go 语言的 channel

Go语言Channel详解

channel

Go 语言的 channel(通道)是 Go 并发编程中的核心概念之一,
它提供了一种线程安全的方式来在 goroutine 之间传递数据。

通过 channel,可以在不同的 goroutine 之间进行通信和同步。

通道是 Go 的并发模型中的核心工具之一,它使用了“通信顺序进程”(CSP,Communicating Sequential Processes)模型,
允许不同的任务(goroutine)以同步和异步的方式交换数据。

  1. channel 的基本特性

类型安全:channel 的类型在定义时是固定的,一个 channel 只能传输一种类型的数据。

同步通信:如果一个 goroutine 发送数据到 channel,而另一个 goroutine 没有准备好接收数据,发送会被阻塞。
同样,接收者会在没有数据时被阻塞。

无缓冲(默认)和 有缓冲:channel 可以是无缓冲的(默认)或有缓冲的。
无缓冲 channel 会强制发送和接收操作是同步的;有缓冲 channel 则允许异步传输数据,直到缓冲区满。

  1. 创建和使用 Channel

3.1 创建 Channel

Go 使用 make 函数来创建 channel,并通过指定类型来确定 channel 传递的数据类型。你可以选择是否指定缓冲区大小。

无缓冲 Channel(默认)

ch := make(chan int) // 创建一个传输整数的无缓冲 channel

有缓冲 Channel(指定缓冲区大小)

ch := make(chan int, 2) // 创建一个传输整数的缓冲区大小为 2 的 channel

有缓冲的 channel 可以存储一定数量的数据,当缓冲区满时,发送操作将被阻塞,直到有数据被接收。

3.2 发送和接收数据

发送数据:
使用 <- 操作符将数据发送到 channel 中。

ch <- 42 // 将值 42 发送到 channel ch 中

接收数据:
使用 <- 操作符从 channel 中接收数据。

value := <-ch // 从 channel ch 中接收数据,并赋值给变量 value

  1. 通道的阻塞行为

channel 的操作是阻塞的,意思是:

如果发送者没有接收者准备好,发送操作会被阻塞。

如果接收者没有数据,接收操作会被阻塞。

func main() {
	ch := make(chan int) // 创建无缓冲 channel

	go func() {
		fmt.Println("Sending data to channel...")
		ch <- 42 // 阻塞,直到主 goroutine 准备好接收
		fmt.Println("Data sent!")
	}()

	fmt.Println("Receiving data from channel...")
	value := <-ch // 接收数据,阻塞直到数据可用
	fmt.Println("Received:", value)
}
Receiving data from channel...
Sending data to channel...
Data sent!
Received: 42
  1. 使用有缓冲的 Channel

有缓冲的 channel 允许异步发送数据。

发送者可以在缓冲区满之前将数据发送到 channel,而接收者则可以在稍后的时候接收数据。

package main

import "fmt"

func main() {
    ch := make(chan int, 2) // 创建一个缓冲区大小为 2 的 channel

    ch <- 1 // 发送数据到 channel,非阻塞
    ch <- 2 // 发送数据到 channel,非阻塞

    fmt.Println("Received:", <-ch) // 接收数据
    fmt.Println("Received:", <-ch) // 接收数据
}
Received: 1
Received: 2
  1. close 和 range 用法

关闭 Channel:当你不再需要发送数据时,可以通过 close 函数关闭 channel,
通知接收方没有更多的数据会被发送。关闭后的 channel 可以继续接收数据,但无法再发送数据。

package main

import "fmt"

func main() {
    ch := make(chan int, 3) // 创建有缓冲的 channel

    go func() {
        for i := 1; i <= 3; i++ {
            ch <- i
        }
        close(ch) // 发送完所有数据后关闭 channel
    }()

    for value := range ch { // 遍历 channel,直到它关闭
        fmt.Println(value)
    }
}

  1. select 用法

select 语句类似于 switch,但它用于选择多个 channel 操作中的一个。它可以同时等待多个 channel 的事件发生,并在其中一个 channel 可用时执行相应的操作。

package main

import "fmt"

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)

    go func() {
        ch1 <- "Hello from channel 1"
    }()

    go func() {
        ch2 <- "Hello from channel 2"
    }()

    select {
    case msg1 := <-ch1:
        fmt.Println("Received:", msg1)
    case msg2 := <-ch2:
        fmt.Println("Received:", msg2)
    }
}
select 会等待 ch1 或 ch2 中的任何一个 channel 的消息。当其中一个 channel 收到消息时,相应的 case 就会被执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可能只会写BUG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值