Golang并发模型:select进阶

栏目: Go · 发布时间: 7年前

内容简介:最近公司工作有点多,Golang的select进阶就这样被拖沓啦,今天坚持把时间挤一挤,把吹的牛皮补上。前一篇文章当

最近公司工作有点多,Golang的select进阶就这样被拖沓啦,今天坚持把时间挤一挤,把吹的牛皮补上。

前一篇文章 《Golang并发模型:轻松入门select》 介绍了select的作用和它的基本用法,这次介绍它的3个进阶特性。

nil
for-select
select{}

nil 的通道永远阻塞

当 case 上读一个通道时,如果这个通道是 nil ,则该 case 永远阻塞 。这个功能有1个妙用, select 通常处理的是多个通道,当某个读通道关闭了,但不想 select 再继续关注此 case ,继续处理其他 case ,把该通道设置为 nil 即可。

下面是一个合并程序等待两个输入通道都关闭后才退出的例子,就使用了这个特性。

func combine(inCh1, inCh2 <-chan int) <-chan int {
    // 输出通道
    out := make(chan int)

    // 启动协程合并数据
    go func() {
        defer close(out)
        for {
            select {
            case x, open := <-inCh1:
                if !open {
                    inCh1 = nil
                    continue
                }
                out<-x
            case x, open := <-inCh2:
                if !open {
                    inCh2 = nil
                    continue
                }
                out<-x
            }

            // 当ch1和ch2都关闭是才退出
            if inCh1 == nil && inCh2 == nil {
                break
            }
        }
    }()

    return out
}

如何跳出for-select

break 在 select 内的并不能跳出 for-select 循环 。看下面的例子, consume 函数从通道 inCh 不停读数据,期待在 inCh 关闭后退出 for-select 循环,但结果是永远没有退出。

func consume(inCh <-chan int) {
    i := 0
    for {
        fmt.Printf("for: %d\n", i)
        select {
        case x, open := <-inCh:
            if !open {
                break
            }
            fmt.Printf("read: %d\n", x)
        }
        i++
    }

    fmt.Println("combine-routine exit")
}

运行结果:

➜ go run x.go
for: 0
read: 0
for: 1
read: 1
for: 2
read: 2
for: 3
gen exit
for: 4
for: 5
for: 6
for: 7
for: 8
... // never stop

既然 break 不能跳出 for-select ,那怎么办呢?给你3个锦囊:

  1. 在满足条件的 case 内,使用 return ,如果有结尾工作,尝试交给 defer 。
  2. 在 select 外 for 内使用 break 挑出循环,如 combine 函数。
  3. 使用 goto 。

select{} 永远阻塞

select{} 的效果等价于创建了1个通道,直接从通道读数据:

ch := make(chan int)
<-ch

但是,这个写起来多麻烦啊!没 select{} 简洁啊。

但是,永远阻塞能有什么用呢!?

当你开发一个并发程序的时候, main 函数千万不能在子协程干完活前退出啊,不然所有的协程都 被迫退出 了,还怎么提供服务呢?

比如,写了个Web服务程序,端口监听、后端处理等等都在子协程跑起来了, main 函数这时候能退出吗?

select应用场景

最后,介绍下我常用的 select 场景:

select

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

Computational Geometry

Computational Geometry

Mark de Berg、Otfried Cheong、Marc van Kreveld、Mark Overmars / Springer / 2008-4-16 / USD 49.95

This well-accepted introduction to computational geometry is a textbook for high-level undergraduate and low-level graduate courses. The focus is on algorithms and hence the book is well suited for st......一起来看看 《Computational Geometry》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具