Go-Channel

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270