第012节:缓冲通道

一、非缓冲通道

之前学习的所有通道基本上都没有缓冲。发送和接收到一个未缓冲的通道是阻塞的。

一次发送操作对应一次接收操作,对于一个goroutine来讲,它的一次发送,在另一个goroutine接收之前都是阻塞的。同样的,对于接收来讲,在另一个goroutine发送之前,它也是阻塞的。

二、缓冲通道

缓冲通道就是指一个通道,带有一个缓冲区。发送到一个缓冲通道只有在缓冲区满时才被阻塞。类似地,从缓冲通道接收的信息只有在缓冲区为空时才会被阻塞。

可以通过将额外的容量参数传递给make函数来创建缓冲通道,该函数指定缓冲区的大小。

语法:

ch := make(chan type, capacity)  

上述语法的容量应该大于0,以便通道具有缓冲区。默认情况下,无缓冲通道的容量为0,因此在之前创建通道时省略了容量参数。

三、示例代码

以下的代码中,chan通道,是带有缓冲区的。

package main

import (
    "fmt"
    "strconv"
    "time"
)

func main() {
    /*
    非缓存通道:make(chan T)
    缓存通道:make(chan T ,size)
        缓存通道,理解为是队列:

    非缓存,发送还是接受,都是阻塞的
    缓存通道,缓存区的数据满了,才会阻塞状态。。

     */
    ch1 := make(chan int)           //非缓存的通道
    fmt.Println(len(ch1), cap(ch1)) //0 0
    //ch1 <- 100//阻塞的,需要其他的goroutine解除阻塞,否则deadlock

    ch2 := make(chan int, 5)        //缓存的通道,缓存区大小是5
    fmt.Println(len(ch2), cap(ch2)) //0 5
    ch2 <- 100                      //
    fmt.Println(len(ch2), cap(ch2)) //1 5

    //ch2 <- 200
    //ch2 <- 300
    //ch2 <- 400
    //ch2 <- 500
    //ch2 <- 600
    fmt.Println("--------------")
    ch3 := make(chan string, 4)
    go sendData3(ch3)
    for {
        time.Sleep(1*time.Second)
        v, ok := <-ch3
        if !ok {
            fmt.Println("读完了,,", ok)
            break
        }
        fmt.Println("\t读取的数据是:", v)
    }

    fmt.Println("main...over...")
}

func sendData3(ch3 chan string) {
    for i := 0; i < 10; i++ {
        ch3 <- "数据" + strconv.Itoa(i)
        fmt.Println("子goroutine,写出第", i, "个数据")
    }
    close(ch3)
}

运行结果:

第012节:缓冲通道

原创文章,Golang中国出品,文章对应源码下载:https://www.qfgolang.com/?page_id=1973

发表评论

电子邮件地址不会被公开。 必填项已用*标注

联系我们

学习交流群:点击这里给我发消息

QR code