美文网首页
golang之channel用法[转]

golang之channel用法[转]

作者: 10xjzheng | 来源:发表于2020-06-20 17:28 被阅读0次

    转自 Go Channel 高级实践

    用法

    • 超时控制
    • 取最快的结果
    • 限制最大并发数
    • for...range 优先
    • 多个 goroutine 同步响应
    • 非阻塞的 select
    • for{select{}} 终止

    1.超时控制

    // 利用 time.After 实现
    func main() {
        done := do()
        select {
        case <-done:
            // logic
        case <-time.After(3 * time.Second):
            // timeout
        }
    }
    
    func do() <-chan struct{} {
        done := make(chan struct{}, 1)
        go func() {
            // do something
            // ...
            done <- struct{}{}
        }()
        return done
    }
    

    2.取最快的结果

    比较常见的一个场景是重试,第一个请求在指定超时时间内没有返回结果,这时重试第二次,取两次中最快返回的结果使用。
    超时控制在上面有,下面代码部分就简单实现调用多次了。

    func main() {
        ret := make(chan string, 3)
        for i := 0; i < cap(ret); i++ {
            go call(ret)
        }
            fmt.Println(<-ret)
    }
    
    func call(ret chan<- string) {
        // do something
        // ...
        ret <- "result"
    }
    

    3.限制最大并发数

    // 最大并发数为 2
    limits := make(chan struct{}, 2)
    for i := 0; i < 10; i++ {
        go func() {
            // 缓冲区满了就会阻塞在这
            limits <- struct{}{}
            do()
            <-limits
        }()
    }
    

    4.for...range 优先

    for ... range c { do } 这种写法相当于 if _, ok := <-c; ok { do }

    func main() {
        c := make(chan int, 20)
        go func() {
            for i := 0; i < 10; i++ {
                c <- i
            }
            close(c)
        }()
        // 当 c 被关闭后,取完里面的元素就会跳出循环
        for x := range c {
            fmt.Println(x)
        }
    }
    

    5.多个 goroutine 同步响应

    func main() {
        c := make(chan struct{})
        for i := 0; i < 5; i++ {
            go do(c)
        }
        close(c)
    }
    
    func do(c <-chan struct{}) {
        // 会阻塞直到收到 close
        <-c
        fmt.Println("hello")
    }
    

    6.非阻塞的 select

    select 本身是阻塞的,当所有分支都不满足就会一直阻塞,如果想不阻塞,那么一个什么都不干的 default 分支是最好的选择

    select {
    case <-done:
        return
    default:   
    }
    

    7.for{select{}} 终止

    尽量不要用 break label 形式,而是把终止循环的条件放到 for 条件里来实现

    for ok {
        select {
        case ch <- 0:
        case <-done:
            ok = false
        }
    }
    

    相关文章

      网友评论

          本文标题:golang之channel用法[转]

          本文链接:https://www.haomeiwen.com/subject/wilgxktx.html