zoukankan      html  css  js  c++  java
  • golang中channel的用法

    参考:https://www.jianshu.com/p/066455276de7

    channel有点类似于管道,它在goroutine同步与通信中,有着起承转合的作用,同时也是Golang实现CSP模型的关键

    package main
    
    func main() {
        senderOnly := make(chan<- int)   // 只能用来发送(管道的入口,只进不出)
        receiverOnly := make(<-chan int) // 只能用来接收(管道的出口,只出不进)
        unbuffer := make(chan int)       // 无缓冲可收发
        buffer := make(chan int, 2)      // 无缓冲可收发
        println(senderOnly, receiverOnly, unbuffer, buffer)
    }
    

    以下是channel的一些使用场景

    等待goroutine完成

    package main
    
    func main() {
        println("start main")
        ch := make(chan bool)
        go func() {
            println("come into goroutine")
            ch <- true
        }()
    
        println("do something else")
        <-ch
        close(ch)
    
        println("end main")
    }
    

    在playground中运行
    打印结果:

    start main
    do something else
    come into goroutine
    end main
    

    多个goroutine协同

    三个功能不相关的goroutine最后结果要汇总累加到result

    package main
    
    func main() {
        println("start main")
        ch := make(chan int)
    
        var result int
        go func() {
            println("come into goroutine1")
            var r int
            for i := 1; i <= 10; i++ {
                r += i
            }
            ch <- r
        }()
    
        go func() {
            println("come into goroutine2")
            var r int = 1
            for i := 1; i <= 10; i++ {
                r *= i
            }
            ch <- r
        }()
    
        go func() {
            println("come into goroutine3")
            ch <- 11
        }()
    
        for i := 0; i < 3; i++ {
            result += <-ch
        }
        close(ch)
        println("result is:", result)
        println("end main")
    }
    

    在playground中运行
    其中一组打印结果:

    start main
    come into goroutine3
    come into goroutine2
    come into goroutine1
    result is: 3628866
    end main
    

    Select

    两个goroutine无直接关联,但其中一个先达到某一设定条件便退出或超时退出

    package main
    
    import "time"
    
    func main() {
        println("start main")
        cond1 := make(chan int)
        cond2 := make(chan uint64)
    
        go func() {
            for i := 0; ; i++ {
                cond1 <- i
            }
        }()
    
        go func() {
            var i uint64
            for ; ; i++ {
                cond2 <- i
            }
        }()
    
        endCond := false
        for endCond != true {
            select {
            case a := <-cond1:
                if a > 99 {
                    println("end with cond1")
                    endCond = true
                }
            case b := <-cond2:
                if b == 100 {
                    println("end with cond2")
                    endCond = true
                }
            case <-time.After(time.Microsecond):
                println("end with timeout")
                endCond = true
            }
        }
    
        println("end main")
    }
    

    在playground中运行
    其中打印结果有可能是:

    start main
    end with cond1
    end main
    

    也有可能是:

    start main
    end with timeout
    end main
    

    也可能是:

    start main
    end with cond2
    end main
    

    这说明循环100次大概需要1微秒的时间

    channel与range

    package main
    
    import "fmt"
    
    func main() {
        println("start main")
        ch := make(chan int, 4)
        go func() {
            for i := 0; i < 10; i++ {
                ch <- i
            }
            // 如果不关闭channel,会引发panic
            close(ch)
        }()
    
        for v := range ch {
            fmt.Println(v)
        }
        println("end main")
    }
    

    打印结果为:

    start main
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    end main
    

    无缓冲channel

    package main
    
    func main() {
        var ch = make(chan int)
        ch <- 1
        println(<-ch)
    }
    

    在playground中运行
    打印结果为:

    fatal error: all goroutines are asleep - deadlock!
    
    goroutine 1 [chan send]:
    main.main()
        /tmp/sandbox117018544/main.go:5 +0x60
    

    死锁了,为什么会这样呢,因为ch是一个无缓冲的channel,在执行到ch <- 1就阻塞了当前goroutine(也就是main函数所在的goroutine),后面打印语句根本没机会执行

    稍加修改即能正常运行
    在playground中运行

    package main
    
    func main() {
        var ch = make(chan int)
        go func() {
            ch <- 1
            println("sender")
        }()
        println(<-ch)
    }
    

    因为此时ch既有发送也有接收而且不在同一个goroutine里面,此时它们不会相互阻塞



    作者:wu_sphinx
    链接:https://www.jianshu.com/p/066455276de7
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    HTTP 状态码
    Buffer 流文件
    事件(Event)机制 .on() .emit() .once() .removeListener()
    UDP node客户端和服务端
    node全局变量  node定时器 系统自带的模块 http服务器
    标题省略,不会自动换行
    SpringBoot 出现 Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported
    循环对象
    npm
    根据对象的key值,查找对应的属性value
  • 原文地址:https://www.cnblogs.com/show58/p/12654431.html
Copyright © 2011-2022 走看看