Go语言学习笔记-通道

之前学习的Goroutine可以让我们便捷的进行并行编程,而通道则可以让我们方便的实现Goroutine之间的通信。

一个简单的通道使用示例:

package main

import (
    "fmt"
    "time"
)

func slowFunc(c chan string) {
    time.Sleep(time.Second * 2)
    c <- "slowFunc() finished"
}

func main() {
    c := make(chan string)
    go slowFunc(c)

    msg := <-c
    fmt.Println(msg)
}

这个Go程序中,我们定义了一个传送消息类型为string的通道,我们还开启了一个Goroutine,主函数执行到msg := <-c时会阻塞,直到收到一条从通道c发来的消息为止。

 

通道还具有缓冲的功能,下面的程序我们使用了一个缓冲区大小为2的通道:

package main

import (
    "fmt"
    "time"
)

func receiver(c chan string) {
    for msg := range c {
        fmt.Println(msg)
    }
}

func main() {
    messages := make(chan string, 2)
    messages <- "hello"
    messages <- "world"
    close(messages)
    fmt.Println("Pushed two messages onto channel with no receivers")
    time.Sleep(time.Second * 1)
    receiver(messages)
}

运行该程序可知,即使调用close()关闭了通道后,已发送的消息依然保留在通道的缓冲中,只是无法再向通道发送消息。在receiver()函数中我们接收了通道中的所有消息并打印。

 

在实际项目中,我们很可能需要使用一个通道不断地传送数据,借助for语句我们可以实现这一点:

package main

import (
    "fmt"
    "time"
)

func pinger(c chan string) {
    t := time.NewTicker(1 * time.Second)
    for {
        c <- "ping"
        <-t.C
    }
}

func main() {
    messages := make(chan string)
    go pinger(messages)
    for {
        msg := <-messages
        fmt.Println(msg)
    }
}

此例为不断地通过通道发送和接收数据。

 

除此之外,还有select语句,它类似于switch语句,会执行最先收到消息的通道的case语句

package main

import (
    "fmt"
    "time"
)

func ping1(c chan string) {
    time.Sleep(time.Second * 1)
    c <- "ping on channel1"
}

func ping2(c chan string) {
    time.Sleep(time.Second * 2)
    c <- "ping on channel2"
}

func main() {
    channel1 := make(chan string)
    channel2 := make(chan string)

    go ping1(channel1)
    go ping2(channel2)

    select {
    case msg1 := <-channel1:
        fmt.Println("received", msg1)
    case msg2 := <-channel2:
        fmt.Println("received", msg2)
    }
}

从此程序可知,接收到一条消息后,select语句将不再阻塞。

 

如果不想select语句无限的阻塞,可以专门使用一个通道来接收退出消息,称之为退出通道,如下:

package main

import (
    "fmt"
    "time"
)

func sender(c chan string) {
    for {
        c <- "I'm sending a message"
        time.Sleep(time.Second * 1)
    }
}

func stopFunc(c chan bool) {
    time.Sleep(time.Second * 2)
    fmt.Println("Time's up!")
    c <- true
}

func main() {
    messages := make(chan string)
    stop := make(chan bool)
    go sender(messages)
    go stopFunc(stop)

    for {
        select {
        case <- stop:
            return
        case msg:= <- messages:
            fmt.Println(msg)
        }
    }
}

 

posted @ 2019-04-08 12:14  鞭挞代码  阅读(347)  评论(0编辑  收藏  举报