美文网首页
Go-Channel

Go-Channel

作者: 骑蜗上高速 | 来源:发表于2019-12-24 17:55 被阅读0次

    goroutine特性:

    主goroutine 结束,子goroutine退出
    

           

    package main
    import (
    "fmt"
    "time"
    )
    func Newtask() {
    i := 0
    for {
        i ++
        fmt.Printf("new goroutine i=%d\n",i)//打印输出
        time.Sleep(time.Second)//暂停一秒,cpu时间会被其他goroutine获取到。
    }
    }
    // 主goroutine(main函数)
    //主goroutine和子goroutine同时在执行,同时获取cpu时间
    func main() {
    go Newtask()//子goroutine(Newtask)
    i := 0
    for {
        i++
        fmt.Printf("main goroutine i=%d\n",i)//打印输出
        time.Sleep(time.Second)//暂停一秒,cpu时间会被其他goroutine获取到。
    }
    }
    

    runtime.Gosched():
    出让当前cpu时间片,当再次获得cpu时,从出让位置继续恢复执行。

    runtime.Goexit():
    return:返回当前函数调用到调用者那里。return之前defer注册生效;
    goexit():结束调用该函数的当前goroutine,goexit()之前注册的defer生效。

    runtime.GOMAXPROCES:
    设置当前进程使用的最大cpu核数,返回上一次调用成功的设置值,首次调用返回默认值。

    channle:
    一只数据类型,对应一个管道,先进先出。主要用来解决goroutine同步问题以及协程之间的数据共享(数据传递)问题。 goroutine运行在相同的地址空间,通过通信来共享内存。

    要求:channel 的读写必须同时满足,才能进行数据流通。
    
    image
    package main
    import (
    "fmt"
    "time"
    )
    //定义一个全局管道
    var ch = make(chan int)
    //定义一台打印机
    func printer(s string) {
    for _,st := range s {
        fmt.Printf("%c",st)
        time.Sleep(time.Second)
    }
    }
    //定义两个人使用打印机
    func person1() {
    printer("Hello")
    ch <- 8//朝管道中写入8
    }
    func person2() {
    <- ch //读取管道中内容。person1使用打印机完毕钱,一直阻塞
    printer("World")
    }
    func main () {
    go person1()
    go person2()
    for {
        ;
    }
    }
    
    image image

    无缓冲channel:
    通道容量为0,len=0,不能存储数据,channel应用于两个goroutine中,一个读,一个写。必须读写同步。(理解为打电话)
    有缓冲channel:
    通道容量非0,len(ch) :channel中剩余的未读区的个数,channel应用于两个goroutine中,一个读,一个写。缓冲区可以进行数据存储。存储到容量上限后,才会阻塞。具备异步能力。(理解为发短信,不需要两个goroutine同时在线,不需要同时操作channel缓冲区)


    有缓冲区:

    package main
    import (
    "fmt"
    "time"
    )
    
    func main() {
    ch := make(chan int, 3)
    //存满超过3个后,就会阻塞。直到主goroutine读取出这3个数据后,
    // 管道为空了,然后会重新写入数据。
    go func() {
        for i := 0; i < 8; i++ {
            ch <- i
            //time.Sleep(time.Second)
            fmt.Println("子goroutine在执行...i=", i)
        }
    }()
        //启动时刻。主goroutine暂停三秒,因channel是带有缓冲区的,所以并不会发生阻塞现        象。
    // 子goroutine继续朝管道中写入数据,并执行打印。三秒后,主gouroutine读取数据,并  打印。
    time.Sleep(time.Second * 3)
    for i := 0; i < 8; i++ {
        num := <-ch
        fmt.Println("主goroutine在执行..num=", num)
      }
    }
    

    关闭channel:
    使用close(ch) 关闭channel
    对端可以判断channel是否关闭:
    遍历channel
    1、 if num, ok := <- ch; ok == bool {
    如果对端已经关闭channel,那么ok--->false, num无数据
    如果对端没有关闭channel,那么ok-->true,num存储读取到的数据。
    }
    2、for num := range ch {
    }
    1、数据不发送完,不应该关闭channel。
    2、已经关闭的channel不能在里面写数据。
    3、已经关闭的channel可以从里面读取 。读取的数据是0
    关闭channel:

    package main
    import (
    "fmt"
    "time"
    )
    
    func main ()  {
    ch := make(chan int)
    go func() {
        for i := 0; i < 5; i ++ {
            ch <- i
            fmt.Println("子goroutine正在执行i=",i)
        }
        close(ch)
    }()
    time.Sleep(time.Second*3)
    for {
        if num, ok := <- ch; ok == true {
            fmt.Println("主goroutine正在执行,读取的数据是num =",num)
        }else {
            fmt.Println("主goroutine结束,因为子goroutine已经关闭了channel。")
            break
        }
        }
    }
    

    单向channel:
    默认双向channel
    单向写channel:var writeCh chan <- int writeCh := make(chan <- int)
    单向读channel var readCh < - chan int readCh := make(<- chan)
    转换:
    1、双向channel可以隐士转换为任意一种单向channel。
    writeCh = ch
    2、单向channel不能转换为双向channel。
    传参:传(引用参数)

    package main
    import "fmt"
    func send (out chan <- int) {
    out <- 888
    close(out)
    }
    func recv (in <- chan int){
    num := <- in
    fmt.Println("读到的数据是:",num)
    }
    func main () {
    ch := make(chan int)//双向channel
    go func() {
        send(ch)//双向channel转换为单向写channel
    }()
    recv(ch)
    }
    

    生产者和消费者模型:
    生产者->缓冲区->消费者
    缓冲区:1、解藕(降低生产者和消费者的耦合度)2、提高并发 3、缓存
    生产者:发送数据端
    消费者:接收数据端
    代码示例:

    package main
    
    import (
    "fmt"
    "time"
    )
    //生产者
    func producer(out chan <- int) {
          for i :=0; i < 10; i++ {
            fmt.Println("生产数据:",i * i)
            out <- i * i
    }
        close(out)//记得关闭channel
    }
    //消费者
    func consummer(in <- chan int) {
          for num := range in {
            fmt.Println("消费数据",num)
            time.Sleep(time.Second)
    }
    }
    func main () {
    //ch := make(chan int)//无缓冲channel,生产者和消费者同步通信(并行输出)
    ch := make(chan int,5)//有缓冲channel,生产者和消费者异步通信(异步输出)
        go producer(ch)
        consummer(ch)
    }
    

    定时器:
    创建定时器,指定时常,定时到达后,系统会自动朝定时器的成员C写入当前系统时间(对chan 写操作)
    Timer定时器

      type Timer struct {
          C <-chan Time
          r runtimeTimer
        }
    

    代码示例:

      package main
    
      import (
            "fmt"
            "time"
      )
    
      func main() {
          fmt.Println("当前时间是", time.Now())
          timer := time.NewTimer(time.Second * 1)
          times := <-timer.C
          fmt.Println("读取的时间是", times)
      }
    

    Ticker定时器(周期定时 ):
    1、 定时时长到达后,系统会自动向Ticker的C中写入系统当前时间,并且每隔一个定时时常后,循环写入系统当前时间。
    2、在子goroutine中循环读取C,获取系统时间。

      type Ticker struct {
        C <-chan Time // The channel on which the ticks are delivered.
        r runtimeTimer
      }
    

    代码示例:

    package main
    
    import (
        "fmt"
        "runtime"
        "time"
    )
    func main()  {
        //fmt.Println("now",time.Now())
        quit := make(chan bool)
        myTicker := time.NewTicker(time.Second)
        i := 0
        go func() {
            for {
                nowTime := <- myTicker.C
                i ++
                fmt.Println("nowTime:",nowTime)
                if i == 6 {
                    quit <- true //解锁主goroutine
                    runtime.Goexit()//退出
                }
            }
        }()
    
         <- quit //循环获取<- myTicker.C 期间,一直会阻塞。 直到 i=6 秒后有数据后,从管道中读取。
    }
    

    输出结果:

    nowTime: 2019-12-25 16:34:00.096712652 +0800 CST m=+1.003466126
    nowTime: 2019-12-25 16:34:01.098549988 +0800 CST m=+2.005273409
    nowTime: 2019-12-25 16:34:02.093829183 +0800 CST m=+3.000522748
    nowTime: 2019-12-25 16:34:03.094870846 +0800 CST m=+4.001534381
    nowTime: 2019-12-25 16:34:04.094038169 +0800 CST m=+5.000671731
    nowTime: 2019-12-25 16:34:05.094124791 +0800 CST m=+6.000728353
    
    Process finished with exit code 0
    

    相关文章

      网友评论

          本文标题:Go-Channel

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