This page looks best with JavaScript enabled

Select -- 无阻塞读写 channel

 ·  ☕ 2 min read · 👀... views

通道阻塞

在之前的 Go 的并发模型 可以了解到,FAN 流水模型可以多个 Goroutine 读一个 Channel 中的数据(FAN-OUT),或者多个 Chanel 将数据发送到一个 Goroutine 中接收(FAN-IN),但是无论是无缓冲通道,还是有缓冲通道,都存在阻塞的情况

无缓冲通道

特点:发送的数据需要被读取后,发送才会完成

阻塞场景:

  • 通道中无数据,但执行都通道
  • 通道中无数据,向通道中写数据,但无其他协程读取该通道中的数据

代码示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 场景 1
func ReadNoDataFromNoBufCh(){
    noBufCh := make(chan int)
    // 通道中无数据
    <- noBufCh
    fmt.Println("read from no buffer channel success")

    // Output:
    // fatal error: all goroutines are asleep - deadlock!
}

// 场景 2
func WriteNoBufCh(){
    ch := make(chan int)
    ch <- 1
    fmt.Println("write success no block")

    // Output:
    // fatal error: all goroutines are asleep - deadlock!
}

有缓冲通道

特点:有缓存时可以向通道中写入数据后直接返回,缓存中有数据时可以从通道中读到数据直接返回,这时有缓存通道是不会阻塞的

阻塞场景:

  • 通道的缓存无数据,但执行读通道
  • 通道的缓存已经占满,向通道写数据,但无协程读

代码示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 场景 1
func ReadNoDataFromBufCh(){
    bufCh := make(chan int, 1)
    // 通道中无数据
    <- bufCh
    fmt.Println("read from no buffer channel success")

    // Output:
    // fatal error: all goroutines are asleep - deadlock!
}

// 场景 2
func WriteBufChButFull(){
    ch := make(chan int, 1)
    // 写数据,占满缓冲
    ch <- 1
    
    // 无协程读取缓冲中的数据,继续写,阻塞
    ch <- 2
    fmt.Println("write success no block")

    // Output:
    // fatal error: all goroutines are asleep - deadlock!
}

Select 功能

Select 由关键字 selectcase 组成,default 不是必须的,如果没其他事可做,可以省略 default在多个通道上进行读或写操作,让函数可以处理多个事情,但 1 次只处理 1 个,有以下特性:

  • 每次执行 select,都会只执行其中 1 个 case 或者执行 default 语句
  • 当没有 case 或者 default 可以执行时,select 则阻塞,等待直到有 1 个 case 可以执行
  • 当有多个 case 可以执行时,则随机选择 1 个 case 执行
  • case 后面跟的必须是读或者写通道的操作,否则编译出错
Share on

睡沙发の沙皮狗
WRITTEN BY
睡沙发の沙皮狗
👨‍💻 Backend Developer/📚 Learner/🚀 Opensource enthusiast

 

What's on this Page