什么是管道Channel

为了解决与Groutines间的通讯问题,Go中提供给了管道Channel。Channel有点像是Linux系统的双向通讯管道,既可以发送消息,也可以接受消息。管道需要明确处理的数据类型,也就是在声明管道时必须还要声明类型。管道的定义方法如下:

ci := make(chan int)
cs := make(chan string)
cf := make(chan interface{
   })

管道的使用

创建

我们建立这样的一个管道,这是一个没有任何缓存的bool型管道

ch := make(chan bool)

也可以通过指定缓冲区大小定义管道的长度,下面示例中缓冲区可以存放两个元素,如果超过2个元素,则会阻塞并等待取走管道后,再进行写入,后续会有示例来详细讲解

ch := make(chan bool, 2)

读取

这是读取管道的方法,程序运行时,将产生阻塞,直到从管道内读取到值

value := <- ch

读取时,管道内将返回两个值,其中第二个值可以作为channel是否关闭的判断条件,以帮助我们更好的控制并发

value, open := <-ch
if !open {
   
    fmt.Println("Channel is already closed")
}

写入

这是写入管道的方法,程序运行时,也将阻塞,一直等待有人将值读取走

ch <- true

单并发使用示例

我们尝试来解决上一节遗留的问题,我们通过Channel在主函数中等待Channel实现异步的控制。
我们首先声明了一个channel,用于传输整数

ch := make(chan int)

在ready函数中,我们在函数最后将运行时间输入管道之中

c <- s

而在主函数中,我们读取管道内返回的值,这里管道其实并没有关闭,所以ok中返回的值仍然为true,管道仍然是打开状态

value, ok := <- ch

这是完整的示例

package main

import (
    "fmt"
    "time"
)

func ready(s int, c chan int) {
   
    fmt.Printf("Run func in a goroutine and wait for %v\n", s)
    time.Sleep(time.Second * time.Duration(s))
    fmt.Printf("Run func in a goroutine and wait for %v end\n", s)

    // Save wait interval to channel
    c <- s

    close(c)
}

func main() {
   

    ch := make(chan int)

    mainWaitSec := 2
    go ready(5, ch)

    fmt.Printf("Run Main function and wait for %v\n", mainWaitSec)
    time.Sleep(time.Second * time.Duration(mainWaitSec))
    fmt.Printf("Run Main function and wait for %v done\n", mainWaitSec)


    value, ok := <- ch
    fmt.Printf("Channel return value: %v\n", value