• golang中channel的用法


    空(nil)读写阻塞,写关闭异常,读关闭空零

    给⼀个 nil channel 发送数据,造成永远阻塞 ▪ 从⼀个 nil channel 接收数据,造成永远阻塞

    给⼀个已经关闭的 channel 发送数据,引起 panic ▪ 从⼀个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回⼀个零值

    ⽆缓冲的channel是同步的,⽽有缓冲的channel是⾮同步的

    close(ch)关闭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")
    }

    打印结果:

    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")
    }

    其中一组打印结果:

    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")
    }
    

    其中打印结果有可能是:

    start main
    end with cond1
    end main

    也有可能是:

    start main
    end with timeout
    end main

    也可能是:

    start main
    end with cond2
    end main

    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)
    }

    打印结果为:

    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),后面打印语句根本没机会执行

    稍加修改即能正常运行

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

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

    package main
    
    func main() {
        var ch = make(chan int)
        ch <- 1
        println(<-ch)
    }
  • 相关阅读:
    什么?Spring Boot CommandLineRunner 有坑!?
    关于 websocket 跨域的一个奇怪问题…
    电商金额计算的 4 个坑,千万注意了!
    微服务模块划分原则和接口定义原则
    tcp的三次握手(连接)与四次挥手(断开)
    二叉树遍历及算法实现
    elasticsearch搜索 倒排索引
    kubernetes落地-传统web服务迁移
    Docker核心技术-容器管理
    Docker核心技术-镜像管理
  • 原文地址:https://www.cnblogs.com/peteremperor/p/13927383.html
Copyright © 2020-2023  润新知