内容简介:通过通过select会随机选择一个未阻塞的通道,如果都阻塞了,则等待直到有一个通道不阻塞。我们也可以通过
无缓冲区通道
通过 make(chan xxx)
创建,没有设置缓冲区大小,这种类型的通道会在两种情况下导致阻塞:
- 通道中无数据,但执行通道读操作。
- 执行通道写操作,但是无协程从通道中读取数据。
// 情况1
func ReadNoDataFromNoBufCh() {
noBufCh := make(chan int)
<-noBufCh
println("read from no buffer channel success")
}
// 情况2
func WriteNoBufCh() {
ch := make(chan int)
ch <- 1
println("write success no block")
}
有缓冲区通道
通过 make(chan xxx, int)
创建,并设置了缓冲区大小。如果缓存区未满,则写入后会立即返回。如果缓冲区有数据,读取后也会立即返回。这种类型的通道会在两种情况下导致阻塞:
- 缓冲区无数据,但执行了通道读操作。
- 缓冲区已满,但执行了通道写操作。
//情况1
func ReadNoDataFromBufCh() {
bufCh := make(chan int, 1)
<-bufCh // 缓冲区无数据,读取失败
println("read from buffer channel success")
}
//情况2
func WriteBufCh() {
ch := make(chan int, 1)
ch <- 1 // 有缓冲区,写入后立即返回
ch <- 2 // 缓冲区已满,无法写入
println("write success no block")
}
Select + Channel
select会随机选择一个未阻塞的通道,如果都阻塞了,则等待直到有一个通道不阻塞。我们也可以通过 default 分支来实现默认的无阻塞操作,具体代码如下:
func ReadNoDataFromNoBuffChWithSelect() {
noBufCh := make(chan int)
if v, err := ReadWithSelect(noBufCh); err != nil {
fmt.Println(err)
} else {
fmt.Printf("read: %d\n", v)
}
}
func ReadNoDataFromBufChWithSelect() {
bufCh := make(chan int, 1)
if v, err := ReadWithSelect(bufCh); err != nil {
fmt.Println(err)
} else {
fmt.Printf("read: %d\n", v)
}
}
func ReadWithSelect(ch chan int) (int, error) {
select {
case x := <-ch:
return x, nil
default:
return 0, errors.New("channel has no data")
}
}
func WriteNoBufChWithSelect() {
ch := make(chan int)
if err := WriteChWithSelect(ch); err != nil {
fmt.Println(err)
} else {
println("success")
}
}
func WriteBufChButFullWithSelect() {
ch := make(chan int, 1)
ch <- 100
if err := WriteChWithSelect(ch); err != nil {
fmt.Println(err)
} else {
println("success")
}
}
func WriteChWithSelect(ch chan int) error {
select {
case ch <- 1:
return nil
default:
return errors.New("channel blocked, can not write")
}
}
定时阻塞
使用 default 实现的无阻塞读写有一个缺点:当通道不可读写时,会立即返回。但是实际场景中,我们可能需要等待一段时间后再返回,使用 定时器 替代default可以解决这个问题,給通道一定的容忍时间,代码如下:
func ReadWithSelectAndTimer(ch chan int) (int, error) {
timeout := time.NewTimer(time.Microsecond * 500)
select {
case x := <-ch:
return x, nil
case <-timeout.C: // 如果500ms内无法读写,就即刻返回
return 0, errors.New("read time out")
}
}
func WriteChWithSelectAndTimer(ch chan int) error {
timeout := time.NewTimer(time.Microsecond * 500)
select {
case ch <- 1:
return nil
case <-timeout.C: // 如果500ms内无法读写,就即刻返回
return errors.New("write time out")
}
}
注意: 如果select写在循环语句当中,并且也用了定时通道,不要在select中每次都NewTimer,在循环外面创建定时器,避免频繁创建。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Golang 并发,有缓存通道,通道同步案例演示
- 科普 | 菜鸟学习状态通道,Part-2:App 定制型状态通道
- golang通道定义
- 通道 | Java NIO
- golang 通道channel 基础
- golang通道channel高级
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java编程思想
[美] Bruce Eckel / 陈昊鹏、饶若楠 / 机械工业出版社 / 2005-9 / 95.00元
本书赢得了全球程序员的广泛赞誉,即使是最晦涩的概念,在Bruce Eckel的文字亲和力和小而直接的编程示例面前也会化解于无形。从Java的基础语法到最高级特性(深入的面向对象概念、多线程、自动项目构建、单元测试和调试等),本书都能逐步指导你轻松掌握。 从本书获得的各项大奖以及来自世界各地的读者评论中,不难看出这是一本经典之作。本书的作者拥有多年教学经验,对C、C++以及Java语言都有独到......一起来看看 《Java编程思想》 这本书的介绍吧!
Markdown 在线编辑器
Markdown 在线编辑器
UNIX 时间戳转换
UNIX 时间戳转换