channel 和阻塞模式和非阻塞模式(1)

2020-07-16  本文已影响0人  上弦月Tt

最近一直又被问到chan 的阻塞和非阻塞模式有什么区别,他们分别在什么场景下使用,写个日记记录下

阻塞模式

示例代码

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    ch <- 1
    time.Sleep(3 * time.Second)
    i := <-ch
    fmt.Println(i)
}

很明显以上代码会报错fatal error: all goroutines are asleep - deadlock!,非阻塞channel同一时刻必须有读端(i=:<-ch)和写端(ch <- 1),可以理解为一个同步过程,所以有的地方把他叫做同步通道, 修改代码如下就可以正常运行.

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    go func() {
        ch <- 1
        time.Sleep(3 * time.Second)
    }()
    i := <-ch
    fmt.Println(i)
}

应用场景:阻塞主程序,如果能捕获系统Interrupt信号,则退出主程序,执行清理工作, 示例代码如下

func Consumer() {
    // do something
    stop := make(chan os.Signal)

    signal.Notify(stop, os.Interrupt)
    <-stop
    endProcess()
}

func endProcess() {
    fmt.Println("我来结束程序")
    time.Sleep(3 * time.Second)
}

如果使用select 程序永远都不会报fatal error: all goroutines are asleep - deadlock!如下所示

package main

import (
    "fmt"
    "time"
)

func main() {
    messages := make(chan string)
    signals := make(chan bool)

    select {
    case msg := <-messages:
        fmt.Println("received message", msg)
    default:
        fmt.Println("no message received")
    }

    go func() { messages <- "hi" }()
    time.Sleep(1 * time.Second)
    

    select {
    case msg := <-messages:
        fmt.Println("received message", msg)
    case sig := <-signals:
        fmt.Println("received signal", sig)
    default:
        fmt.Println("no activity")
    }
}

明天争取把非阻塞的通道补上。

上一篇下一篇

猜你喜欢

热点阅读