Go语言 之有缓冲的channel

l 在第 1 步,右侧的 goroutine 正在从通道接收一个值。

l 在第 2 步,右侧的这个 goroutine独立完成了接收值的动作,而左侧的 goroutine 正在发送一个新值到通道里。

l 在第 3 步,左侧的goroutine 还在向通道发送新值,而右侧的 goroutine 正在从通道接收另外一个值。这个步骤里的两个操作既不是同步的,也不会互相阻塞。

l 最后,在第 4 步,所有的发送和接收都完成,而通道里还有几个值,也有一些空间可以存更多的值。

 

有缓冲的通道(buffered channel)是一种在被接收前能存储一个或者多个数据值的通道。

这种类型的通道并不强制要求 goroutine 之间必须同时完成发送和接收。通道会阻塞发送和接收动作的条件也不同。

只有通道中没有要接收的值时,接收动作才会阻塞。

只有通道没有可用缓冲区容纳被发送的值时,发送动作才会阻塞。

这导致有缓冲的通道和无缓冲的通道之间的一个很大的不同:无缓冲的通道保证进行发送和接收的 goroutine 会在同一时间进行数据交换;有缓冲的通道没有这种保证。

 

package main

import (
    "fmt"
    "time"
)

func main() {
    //带缓冲的通道
    c := make(chan int, 3)
    //内置函数 len 返回未被读取的缓冲元素数量, cap 返回缓冲区大小
    fmt.Printf("len(c)=%d, cap(c)=%d\n", len(c), cap(c))
    go func() {
        defer fmt.Println("子协程结束")

        for i := 0; i < 3; i++ {
            c <- i
            fmt.Printf("子协程正在运行[%d]: len(c)=%d, cap(c)=%d\n", i, len(c), cap(c))
        }
    }()

    time.Sleep(2 * time.Second) //延时2s
    for i := 0; i < 3; i++ {
        num := <-c //从c中接收数据,并赋值给num
        fmt.Println("num = ", num)
    }
    fmt.Println("main协程结束")

    //执行结果:
    /*
        len(c)=0, cap(c)=3
        子协程正在运行[0]: len(c)=1, cap(c)=3
        子协程正在运行[1]: len(c)=2, cap(c)=3
        子协程正在运行[2]: len(c)=3, cap(c)=3
        子协程结束
        num =  0
        num =  1
        num =  2
        main协程结束
    */
}

 

posted @ 2019-07-04 13:20  样子2018  阅读(470)  评论(0编辑  收藏  举报