zoukankan      html  css  js  c++  java
  • Go 信道(channel)

    什么是信道?

    信道可以想像成 Go 协程之间通信的管道。如同管道中的水会从一端流到另一端,通过使用信道,数据也可以从一端发送,在另一端接收。

    信道的声明

    package main
    
    import (
        "fmt"
        "time"
    )
    
    //不同goroutine之间通信
    //通过channel实现
    
    func main() {
        //1 定义channel
        var c chan int
        //2 信道的零值(引用类型,空值为nil,当做参数传递时,不需要取地址,改的就是原来的,需要初始化再使用)
        fmt.Println(c)
        //3 信道初始化
        c=make(chan int)  //数字暂时先不关注
        //4 信道的放值  (注意赋值和放值)
        //c<-1
        //c=12  //赋值报错
        //5 信道取值
        //<-c
        //6 取出来赋值给一个变量 int
        //var a int
        //a=<-c
        //a:=<-c
    
        //7 信道默认不管放值还是取值,都是阻塞的
    
        //c是引用类型
        go test1(c)
    
        a:=<-c  //阻塞   不但实现了两条协程之间通信,还实现了等待协程执行结束
        fmt.Println(a)
    
    }
    
    func test1(a chan int)  {
        fmt.Println("go go go ")
        time.Sleep(1*time.Second)
        //往信道中放一个值
        a<-10 //阻塞
    
    
    }

    信道小例子

    package main
    
    //信道小例子
    //程序有一个数中 每一位的平方和与立方和,然后把平方和与立方和相加并打印出来
    
    import (
        "fmt"
        "time"
    )
    
    func calcSquares(number int, squareop chan int) {
        sum := 0  //总和
        for number != 0 {
            digit := number % 10   //589对10取余数,9   8   5
            sum += digit * digit  //sum=9*9   8*8     5*5
            number /= 10         //num=58    5       0
        }
        time.Sleep(2*time.Second)
        squareop <- sum
    }
    
    func calcCubes(number int, cubeop chan int) {
        sum := 0
        for number != 0 {
            digit := number % 10
            sum += digit * digit * digit
            number /= 10
        }
        time.Sleep(1*time.Second)
        cubeop <- sum
    }
    
    //func calcSquares(number int, squareop chan int) int{
    //    sum := 0  //总和
    //    for number != 0 {
    //        digit := number % 10   //589对10取余数,9   8   5
    //        sum += digit * digit  //sum=9*9   8*8     5*5
    //        number /= 10         //num=58    5       0
    //    }
    //    time.Sleep(2*time.Second)
    //    return sum
    //}
    //
    //func calcCubes(number int, cubeop chan int) int{
    //    sum := 0
    //    for number != 0 {
    //        digit := number % 10
    //        sum += digit * digit * digit
    //        number /= 10
    //    }
    //    time.Sleep(2*time.Second)
    //    return sum
    //}
    
    func main() {
        ctime:=time.Now().Unix()
        fmt.Println(ctime)
        number := 589
        sqrch := make(chan int)
        cubech := make(chan int)
        //num1:=calcSquares(number, sqrch)
        //num2:=calcCubes(number, cubech)
        go calcSquares(number, sqrch)
        go calcCubes(number, cubech)
        squares, cubes := <-sqrch, <-cubech
        //squares:= <-sqrch
        //cubes:=<-cubech
        fmt.Println("Final output", squares + cubes)
        ttime:=time.Now().Unix()
        fmt.Println(ttime)
        fmt.Println(ttime-ctime)
    }

    信道的死锁现象

    package main
    
    import "fmt"
    
    //信道的死锁现象,默认都是阻塞的,一旦有一个放,没有人取  或者一个人取,没有人放,就会出现死锁
    
    //func main() {
    //    //var c chan int =make(chan int )
    //
    //    //c<-1  //其实放不进去,阻塞在这,就死锁了
    //    //<-c     //没有,取不到,阻塞在这,就死锁了
    //
    //}
    
    
    //单向信道
    //func sendData(sendch chan<- int) {
    //    sendch <- 10
    //}
    //
    //func main() {
    //    //sendch := make(chan<- int)   //定义了一个只写信道
    //    sendch := make(chan int)   //定义了一个可读可写信道
    //    go sendData(sendch)        //传到函数中转成只写信道,在goroutine中,只负责写,不能往外读,主协程读
    //    fmt.Println(<-sendch)   //只写信道一旦读,就有问题
    //}
    
    
    
    ///3 关闭信道
    //func main() {
    //    sendch := make(chan int)
    //    //关闭信道
    //    //close(sendch)
    //
    //    //信道可以用for循环循环
    //}
    
    
    // 信道关闭close(sendch) ,for循环循环信道,如果不关闭会报死锁,如果关闭了,放不进去,循环结束
    func producer(chnl chan int) {
        for i := 0; i < 100; i++ {
            fmt.Println("放入了",i)
            chnl <- i
        }
        close(chnl)
    }
    func main() {
        ch := make(chan int)
        go producer(ch)
        for v := range ch {
            fmt.Println("Received ",v)
        }
    }

    缓冲信道

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    //缓冲信道:只在缓冲已满的情况,才会阻塞向缓冲信道,只有在缓冲为空的时候,才会阻塞从缓冲信道接收数据
    
    //func main() {
    //    var c chan int =make(chan int,6)  //无缓冲信道数字是0
    //    c<-1
    //    c<-2
    //    c<-3
    //    c<-4
    //    c<-5
    //    c<-6
    //    //c<-7  //死锁
    //    <-c
    //    <-c
    //    //<-c
    //    //<-c
    //    //<-c
    //    //<-c
    //    //<-c // 取空了,死锁(一个goroutine中会出现)
    //
    //
    //    // 2 长度 vs 容量
    //    //fmt.Println(len(c))  //目前放了多少
    //    //fmt.Println(cap(c)) //可以最多放多少
    //
    //
    //    
    //}
    //3 WaitGroup  等待所有goroutine执行完成
    //4  使用信道如何实现?
    func process1(i int,wg *sync.WaitGroup)  {
        fmt.Println("started Goroutine ", i)
        time.Sleep(2 * time.Second)
        fmt.Printf("Goroutine %d ended
    ", i)
        //一旦有一个完成,减一
        wg.Done()
    }
    
    func main() {
        var wg sync.WaitGroup   //没有初始化,值类型,当做参数传递,需要取地址
        //fmt.Println(wg)
        for i:=0;i<10;i++ {
            wg.Add(1) //启动一个goroutine,add加1
            go process1(i,&wg)
        }
    
        wg.Wait() // 一直阻塞在这,知道调用了10个done,计数器减到零
    }
  • 相关阅读:
    Hadoop学习------Hadoop安装方式之(一):单机部署
    Linux系统上安装、卸载JAVA、TOMCAT的方法
    在Linux系统上安装Oracle数据库
    C:Program Files (x86)MSBuild14.0inMicrosoft.Common.CurrentVersion.targets(4714,5): error MSB30...
    软件设计,数据库结构设计,设计思想
    面试题 SqlServer知识
    @Ajax.ActionLink跳转页面的问题解决方案 MVC Ajax不支持问题
    .net机试题总结
    .Net机试题——编写一个BS架构的多层表结构的信息管理模块
    C# 不同类型对象同名属性赋值
  • 原文地址:https://www.cnblogs.com/ZhZhang12138/p/14886765.html
Copyright © 2011-2022 走看看