使用 Select 在 Go 中进行非阻塞通信标题 | 青训营

274 阅读3分钟

使用 Select 在 Go 中进行非阻塞通信

在 Go 语言中,我们可以使用 select 关键字来实现非阻塞的通信操作。select 类似于 switch,但是用于处理通信操作,可以同时等待多个 channel 的数据到达或者发送数据到多个 channel,而不会因为阻塞而停止执行。

select 的基本用法

select 语句的基本结构如下:

select {
case <-chan1:
    // 如果 chan1 成功读取数据,则执行该 case 处理语句
case chan2 <- 1:
    // 如果成功向 chan2 写入数据,则执行该 case 处理语句
default:
    // 如果上面的 case 都没有成功,则执行 default 处理流程
}

在一个 select 语句中,Go 语言会按顺序从头至尾评估每一个发送和接收的语句。如果其中的任意一条语句可以继续执行(即没有被阻塞),那么就会从那些可以执行的语句中任意选择一条来执行。

如果没有任意一条语句可以执行(即所有的通道都被阻塞),那么有两种可能的情况:

  1. 如果给出了 default 语句,那么就会执行 default 语句,同时程序的执行会从 select 语句后的语句中恢复。
  2. 如果没有 default 语句,那么 select 语句将被阻塞,直到至少有一个通信可以进行下去。

示例代码解析

让我们看一下上述的示例代码,它实现了一个简单的斐波那契数列生成器,并在主函数中通过非阻塞通信打印斐波那契数列的前 6 个数字。

package main
 
import (
    "fmt"
)
 
func fibonacci(c, quit chan int) {
    x, y := 1, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}
 
func main() {
    c := make(chan int)
    quit := make(chan int)
 
    go func() {
        for i := 0; i < 6; i++ {
            fmt.Println(<-c)
        }
        quit <- 0
    }()
 
    fibonacci(c, quit)
}
  • fibonacci 函数是一个生成斐波那契数列的协程,它通过 select 语句实现了两个非阻塞通信操作:

    1. c <- x:将 x 的值发送到通道 c 中,由于 c 是一个缓冲通道,所以在接收方准备好接收之前,这个发送操作不会阻塞。
    2. <-quit:从通道 quit 中接收数据,这里的 quit 通道用于通知协程退出,如果 quit 通道没有数据可接收,那么这个接收操作不会阻塞。
  • main 函数中,我们创建了两个通道 cquit,并分别启动了一个协程来调用 fibonacci(c, quit) 和匿名协程。

  • 匿名协程用于非阻塞地从 c 通道接收数据并打印前 6 个斐波那契数列的值。

  • 最后,main 函数将数据 0 发送到 quit 通道,通知 fibonacci 协程可以退出,从而结束整个程序的执行。

通过使用 select,我们在 fibonacci 函数中实现了非阻塞的通信,使得在通道没有准备好发送或接收数据时,协程不会被阻塞。这样,我们可以更加灵活地处理多个 channel 的通信操作。

总结

select 是 Go 语言中用于处理通信操作的强大工具,通过它,我们可以实现非阻塞的 channel 通信,避免因为发送或接收操作导致的程序阻塞。使用 select 可以在多个 channel 之间进行选择,实现更加灵活和高效的并发编程。在开发过程中,我们应该根据实际情况来选择是否使用 select 来处理 channel 的通信,以便使程序更加高效和健壮。