美文网首页
goroutine 及channel

goroutine 及channel

作者: 不怕天黑_0819 | 来源:发表于2020-10-10 12:04 被阅读0次

    本文主要介绍goroutine 和channel的使用。

    基础知识介绍

    goroutine 是 golang 中在语言级别实现的轻量级线程,仅仅利用 go 就能立刻起一个新线程。多线程会引入线程之间的同步问题,在 golang 中可以使用 channel 作为同步的工具。

    通过 channel 可以实现两个 goroutine 之间的通信。

    创建一个 channel, make(chan TYPE {, NUM}) TYPE 指的是 channel 中传输的数据类型,第二个参数是可选的,指的是 channel 的容量大小。

    向 channel 传入数据, CHAN <- DATA , CHAN 指的是目的 channel 即收集数据的一方, DATA 则是要传的数据。

    从 channel 读取数据, DATA := <-CHAN ,和向 channel 传入数据相反,在数据输送箭头的右侧的是 channel,形象地展现了数据从隧道流出到变量里。

    举三个例子

    
    package main
    /**
    使用通道,类似于多线程计算
     */
    import (
        "fmt"
        "math/rand"
        "time"
    )
    
    func sum(s []int, c chan int) {
        sum := 0
        for _, v := range s {
            time.Sleep(time.Duration(rand.Int31n(10)) * time.Millisecond)
            sum += v
        }
        c <- sum // 把 sum 发送到通道 c
    }
    
    func main() {
        s := []int{7, 2, 8, -9, 4, 0}
    
        c := make(chan int)
        go sum(s[:len(s)/2], c)
        go sum(s[len(s)/2:], c)
        x, y := <-c, <-c // 从通道 c 中接收
    
        fmt.Println(x, y, x+y)
    }
    
    /**
    通道缓冲区, 关闭通道
     */
    
    package main
    
    import (
        "fmt"
    )
    
    func fibonacci(n int, c chan int) {
        x, y := 0, 1
        for i := 0; i < n; i++ {
            c <- x
            x, y = y, x+y
        }
        close(c)
    }
    
    func main() {
        c := make(chan int, 10)
        go fibonacci(cap(c), c)
        // range 函数遍历每个从通道接收到的数据,因为 c 在发送完 10 个
        // 数据之后就关闭了通道,所以这里我们 range 函数在接收到 10 个数据
        // 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数就不
        // 会结束,从而在接收第 11 个数据的时候就阻塞了。
        for i := range c {
            fmt.Println(i)
        }
        fmt.Print("finish")
    }
    
    package main
    
    import (
        "fmt"
        "time"
    )
    
    func say(s string) {
        for i := 0; i < 5; i++ {
            time.Sleep(100 * time.Millisecond)
            fmt.Println(s, (i+1)*100)
        }
    }
    func say2(s string, ch chan int) {
        for i := 0; i < 5; i++ {
            time.Sleep(150 * time.Millisecond)
            fmt.Println(s, (i+1)*150)
        }
        ch <- 0
        close(ch)//关闭通道并不会丢失里面的数据,只是让读取通道数据的时候不会读完之后一直阻塞等待新数据写入
    }
    
    func main() {
        ch := make(chan int)
        go say2("world", ch)
        say("hello")
        fmt.Println(<-ch)//主函数会等待信道的值才会结束。
    }
    
    
    //注释掉的方法,在执行中会发现,say2方法并没有执行完成。这是因为goroutine 还没来得及跑完 5 次的时候,主函数已经退出了。通过引入信道,可以解决这个问题。
    
    /**
    package main
    import (
        "fmt"
        "time"
    )
    func say(s string) {
        for i := 0; i < 5; i++ {
            time.Sleep(100 * time.Millisecond)
            fmt.Println(s, (i+1)*100)
        }
    }
    func say2(s string) {
        for i := 0; i < 5; i++ {
            time.Sleep(150 * time.Millisecond)
            fmt.Println(s, (i+1)*150)
        }
    }
    func main() {
        go say2("world")
        say("hello")
    }
     */
    

    上面三个例子都是关于多线程和线程间通信的例子。

    Channel 控制读写权限

    go func(c chan int) { //读写均可的channel c } (a)
    go func(c <- chan int) { //只读的Channel } (a)
    go func(c chan <- int) { //只写的Channel } (a)

    相关文章

      网友评论

          本文标题:goroutine 及channel

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