Golang 之 协程 goroutine(三)

版权声明:本文为博主原创文章,转载文章须附上文章来源与作者。 https://blog.csdn.net/ChangerJJLee/article/details/81259666

“通道” 是连接多个 Go 协程的管道。 可以从一个 Go 协程, 将值发送到通道,然后在别的 Go 协程中接收。

package main

import "fmt"

func main() {

    // 使用 `make(chan val-type)` 创建一个新的通道。
    // 通道类型就 val-type 是他们需要传递值的类型。
    // 此处创建名为 message 的通道
    messages := make(chan string)

    // 使用 `channel <-` 语法 _发送_ 一个值到通道中。这里
    // 我们在一个新的 Go 协程中发送 `"hello channel"` 到上面创建的`messages` 通道中。
    go func() { messages <- "hello channel" }()

    // 使用 `<-channel` 语法从通道中 _接收_ 一个值。这里
    // 将接收我们在上面发送的 `"hello channel"` 消息并打印出来。
    // 发送和接收操作是阻塞的,直到发送方和接收方都准备完毕。
    // 这个特性允许,不使用任何其它的同步操作,来在程序结尾等待
    // 消息 `"hello channel"`

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

死锁问题: messages <- “hello channel” 与 msg := <-messages 必须同时进行,不然会出现死锁

package main

import "fmt"

func main() {


    messages := make(chan string)
    // 此时已经阻塞在 messages <- "hello channel"
    // 解决方案 1. 在messages <- "hello channel"之前,加协程去消费该通道,或者在消费通道之前加协程往通道发送
    // 解决方案 2. 给messages通道加缓冲防止阻塞
    messages <- "hello channel"
    msg := <-messages
    fmt.Println(msg)
}
// 运行结果
//fatal error: all goroutines are asleep - deadlock!
//goroutine 1 [chan send]:
//main.main()

在准备发送往通道发送数据之前,开启协程去消费通道

package main

import (
    "fmt"
    "time"
)

func f1(msg chan string) {
    fmt.Println(<-msg)
}

func main() {


    messages := make(chan string)
    // 此时已经阻塞在 messages <- "hello channel"
    // 解决方案 1. 在messages <- "hello channel"之前,加协程去消费该通道
    go f1(messages)
    messages <- "hello channel"

    // 防止协程在执行途中,因主线程的结束而终止
    time.Sleep(time.Second * 3)
}

在消费通道之前加协程往通道发送 messages <- “hello channel”

package main

import (
    "fmt"
    "time"
)


func main() {


    messages := make(chan string)
    // 此时已经阻塞在 messages <- "hello channel"
    // 解决方案 1. 在消费通道之前加协程往通道发送 messages <- "hello channel"
    go func() {messages <- "hello channel"}()
    fmt.Println( <-messages )

    // 防止协程在执行途中,因主线程的结束而终止
    time.Sleep(time.Second * 3)
}

通道缓冲 ,给messages通道加缓冲防止阻塞,通道是 无缓冲 的,这意味着只有在对应的接收(<- chan),通道准备好接收时,才允许进行发送(chan <-)。可缓存通道,允许在没有对应接收方的情况下,缓存限定数量的值。

package main

import (
    "fmt"
    "time"
)


func main() {

    // 最多允许缓存一个,此时多发送和多接收,都会引起死锁,所以要保证发送一个,打印一个
    messages := make(chan string, 1)
    // 此时已经阻塞在 messages <- "hello channel"
    // 解决方案 2. 给messages通道加缓冲防止阻塞
    messages <- "hello channel"
    msg := <-messages
    fmt.Println(msg)

    // 防止协程在执行途中,因主线程的结束而终止
    time.Sleep(time.Second * 3)
}

通道同步: 使用通道来同步 Go 协程间的执行状态。这里是一个使用阻塞的接受方式来等待一个 Go 协程的运行结束。

package main

import "fmt"
import "time"

// 这是将要在 Go 协程中运行的函数。
// `done` 通道将被用于通知其他 Go 协程这个函数已经工作完毕。
func worker(done chan bool) {
    fmt.Print("working...")
    time.Sleep(time.Second)
    fmt.Println("done")

    // 发送一个值来通知已经完工。
    done <- true
}

func main() {

    // 运行一个 worker Go协程,并给予用于通知的通道。
    done := make(chan bool, 1)
    go worker(done)

    // 程序将在接收到通道中 worker 发出的通知前一直阻塞。
    fmt.Println("阻塞中")
    <-done
}

猜你喜欢

转载自blog.csdn.net/ChangerJJLee/article/details/81259666