Go 缓冲 channel 和 非缓冲 channel 的区别

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36431213/article/details/83281250
在看本篇文章前我们需要了解阻塞的概念
  • 在执行过程中暂停,以等待某个条件的触发 ,我们就称之为阻塞

在Go中我们make一个channel有两种方式,分别是有缓冲的和没缓冲的
  • 缓冲channelbuffer channel 创建方式为 make(chan TYPE,SIZE)
    • make(chan int,3) 就是创建一个int类型,缓冲大小为3channel
  • 非缓冲channelunbuffer channel 创建方式为 make(chan TYPE)
    • make(chan int) 就是创建一个int类型的非缓冲channel

  • 非缓冲channel 和 缓冲channel 的区别
    • 非缓冲 channelchannel 发送和接收动作是同时发生的
    • 例如 ch := make(chan int) ,如果没 goroutine 读取接收者<-ch ,那么发送者ch<- 就会一直阻塞
    • 缓冲 channel 类似一个队列,只有队列满了才可能发送阻塞

  • 代码演示

  • 非缓冲 channel

package main

import (
	"fmt"
	"time"
)

func loop(ch chan int) {
	for {
		select {
		case i := <-ch:
			fmt.Println("this  value of unbuffer channel", i)
		}
	}
}

func main() {
	ch := make(chan int)
	ch <- 1
	go loop(ch)
	time.Sleep(1 * time.Millisecond)
}
  • 这里会报错 fatal error: all goroutines are asleep - deadlock! 就是因为 ch<-1 发送了,但是同时没有接收者,所以就发生了阻塞
  • 但如果我们把 ch <- 1 放到 go loop(ch) 下面,程序就会正常运行

  • 缓冲 channel 的阻塞只会发生在 channel 的缓冲使用完的情况下
package main

import (
	"fmt"
	"time"
)

func loop(ch chan int) {
	for {
		select {
		case i := <-ch:
			fmt.Println("this  value of unbuffer channel", i)
		}
	}
}

func main() {
	ch := make(chan int,3)
	ch <- 1
	ch <- 2
	ch <- 3
	ch <- 4
	go loop(ch)
	time.Sleep(1 * time.Millisecond)
}

  • 这里也会报 fatal error: all goroutines are asleep - deadlock! ,这是因为 channel 的大小为 3 ,而我们要往里面塞 4 个数据,所以就会阻塞住
  • 解决的办法有两个
    • channel 开大一点,这是最简单的方法,也是最暴力的
    • channel 的信息发送者 ch <- 1 这些代码移动到 go loop(ch) 下面 ,让 channel 实时消费就不会导致阻塞了

猜你喜欢

转载自blog.csdn.net/qq_36431213/article/details/83281250