![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/1af4928aa6b43d08543f6f881d947788.png)
- 什么是协程,作用是什么?
协程是Go语言实现并发处理的一种方式,说成人话就是在一个程序里同时跑两段代码。比如一个普通的函数 func abc() ,当我们执行abc()的时候,主程序会一直等待abc执行完毕之后再继续,这就是所谓的“阻塞”。很显然,程序是以“串行”方式执行的,效率不高。而如果采用协程的话,则只需要在函数名前面加上 go 这个关键字:go func abc() , 这时候,系统将开辟一个新的空间给函数abc去运行,而不会一直等待它执行完毕,也就是说主程序和函数abc是同时运行的,因此也就实现了“并行”的目的。 这时候,主程序和协程之间就不再是通过传统的传参方式去交互变量了。而是通过一种叫做 “通道” 的东西进行交流。 - ch := make(chan bool) 是什么意思?
表示创建一个名为ch的通道,通道中传递的数据类型是布尔型,当然,通道可以传递任意类型,包括自定义类型。譬如说,如果需要在通道中传递字符串类型则:
ch := make(chan string)
chan 是Go语言的一种特殊的数据类型,是英文 channel (通道)的缩写,比如以下这条指令:
v := <-ch
表示:获取ch 通道的变量并存在v里,注意:通道本身并不是变量的值,但是变量的值可以通过通道传递,通道的一头接主程序,另一头接协程。比如在主程序这边我们输入:
ch <- true
意思是说将true这个值发送到通道channel,
然后在协程这边,我们通过:
v := <-ch
从通道中接收从主程序传输过来的值,此时的v就是true. - select case是什么?
用于管理不同的通道,简单地说就是当不同的通道出现新的内容后,该如何处理他们。 - ticker.C 是什么鬼?
就是当前时间,Go定时器在time.NewTicker的时候自动产生了一条通道,按照指定的时间间隔(比如500毫秒)向这条通道发送当前时间(如果你把它打印出来,就是一个当前时间值),如果我们的业务需求并不关注当前时间,可以忽略这个值。可以仅仅看作是一条 “ 时间到了 ” 的信号即可。 - 为什么会出现两个for {} 死循环?
第一个for {} 死循环出现在协程内部,因为协程开启之后就跟主程序无关了,正常情况下协程执行完毕后return就回来了,但显然定时器这种场合是需要一直保持运转的,因此我们看到在协程内部有一个for {} 死循环,这个循环通过select case{} 持续扫描 channel 通道和ticker.C通道的变化,当通道ticker.C发生变化时,执行我们预先指定好的函数,当channel 通道发生变化时,关闭定时器,退出协程。
第二个出现在main主函数里面的for {} 死循环就更容易理解了,它让主程序可以持续运行,否则程序一闪而过,那就没法测试了。
package main
import (
"fmt"
"time"
)
type Timer struct {
Interval int
Tick func()
Channel chan bool
}
func (t Timer) Enabled() {
ticker := time.NewTicker(time.Duration(t.Interval) * time.Millisecond)
go func() {
for {
select {
case <-t.Channel:
ticker.Stop()
return
case <-ticker.C:
t.Tick()
}
}
}()
}
func main() {
tick1 := func() {
fmt.Print(" A ")
}
tick2 := func() {
fmt.Print(" B ")
}
timer1 := new(Timer)
timer1.Interval = 500
timer1.Tick = tick1
timer1.Channel = make(chan bool)
timer1.Enabled()
timer2 := new(Timer)
timer2.Interval = 1000
timer2.Tick = tick2
timer2.Channel = make(chan bool)
timer2.Enabled()
for {
var cmds string
fmt.Scanln(&cmds)
if cmds == "1" {
timer1.Channel <- false
}
if cmds == "2" {
timer2.Channel <- true
}
}
}
- 产生两个独立的定时器,timer1 间隔时间为500ms, timer2间隔时间为1000ms。
- 屏幕上以1秒为一个周期显示字符“A”, 以两秒一个周期显示“B”
- 在主界面输入字符“1”,则停止timer1,输入2则停止timer2。
- 后记
我感觉注释已经说得很清楚了,如果你对Go协程有点了解的话,上面的代码还是很简单的。关于Golang协程的概念还有很多内容,门道还是有点杂的,本文只起一个最简单的抛砖引玉的作用。