Go 通道

栏目: IT技术 · 发布时间: 4年前

内容简介:通过通过select会随机选择一个未阻塞的通道,如果都阻塞了,则等待直到有一个通道不阻塞。我们也可以通过

无缓冲区通道

通过 make(chan xxx) 创建,没有设置缓冲区大小,这种类型的通道会在两种情况下导致阻塞:

  1. 通道中无数据,但执行通道读操作。
  2. 执行通道写操作,但是无协程从通道中读取数据。
// 情况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. 缓冲区无数据,但执行了通道读操作。
  2. 缓冲区已满,但执行了通道写操作。
//情况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,在循环外面创建定时器,避免频繁创建。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

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

智能时代

智能时代

吴军 / 中信出版集团 / 2016-8 / 68.00

大数据和机器智能的出现,对我们的技术发展、商业和社会都会产生重大的影响。作者吴军在《智能时代:大数据与智能革命重新定义未来》中指出,首先,我们在过去认为非常难以解决的问题,会因为大数据和机器智能的使用而迎刃而解,比如解决癌症个性化治疗的难题。同时,大数据和机器智能还会彻底改变未来的商业模式,很多传统的行业都将采用智能技术实现升级换代,同时改变原有的商业模式。大数据和机器智能对于未来社会的影响是全方......一起来看看 《智能时代》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

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

RGB CMYK 互转工具