摄影:产品经理
加油站
在写 Python 的时候,如果想让某个函数每 60 秒执行一次,我们一般这样写代码:
代码语言:javascript复制import time
while True:
some_function()
time.sleep(60)
于是,我在写 Golang 代码的时候,也使用了这种方式:
代码语言:javascript复制package main
import (
"fmt"
"time"
)
func someFunction() {
fmt.Println("我是某个函数")
}
func main() {
for {
someFunction()
time.Sleep(10 * time.Second)
}
}
今天在看同事的代码时,发现他是这样写的:
代码语言:javascript复制package main
import (
"fmt"
"time"
)
func someFunction() {
fmt.Println("我是某个函数")
}
func main() {
tikcer := time.NewTicker(10 * time.Second)
for {
<-tikcer.C
someFunction()
}
}
这种写法,初看起来时候跟time.Sleep
没什么区别,但是仔细一想,却发现它有很多优势。
首先,NewTicker
会在背后计时,时间到了以后,会向内部的一个 channel 中推入当前的时间。然后继续计时。所以,如果函数someFunction()
执行了3秒钟。那么接下来过7秒就会继续执行。但如果使用time.Sleep
,函数执行完成以后,还要再等10秒钟才会执行。
其次,如果不启动新的协程,那么当执行到time.Sleep
时,整个程序是卡住的,必须等待它结束了才能执行后面的操作。但如果使用 NewTicker
,那么在等待的时间,还可以做很多其他的事情。多个不同的定时器可以同时工作:
package main
import (
"fmt"
"time"
)
func someFunction() {
fmt.Println("我是某个函数")
}
func anotherFunction() {
fmt.Println("另一个函数")
}
func thirdFunction() {
fmt.Println("第三个函数")
}
func main() {
tikcer1 := time.NewTicker(10 * time.Second)
tikcer2 := time.NewTicker(5 * time.Second)
tikcer3 := time.NewTicker(3 * time.Second)
for {
select {
case <-tikcer1.C:
someFunction()
case <-tikcer2.C:
anotherFunction()
case <-tikcer3.C:
thirdFunction()
}
}
}
这样可以实现,每3秒执行 thirdFunction
函数,每5秒执行anotherFunction
,每10秒执行一次someFunction
。大家可以考虑一下,如何用 time.Sleep
来实现这样的功能。
注意每个函数都是独立计时的,只要他们执行的时间不超过他们间隔的时间,就不会互相影响。
除了全部用来计时外,我们还可以用来设置外部开关,中断一个协程。例如:
代码语言:javascript复制package main
import (
"fmt"
"time"
)
func doSomething() {
fmt.Println("进行某些操作")
}
func someFunction(stop chan bool) {
fmt.Println("我是某个函数")
tikcer1 := time.NewTicker(10 * time.Second)
for {
select {
case <-tikcer1.C:
doSomething()
case <-stop:
return
}
}
}
func main() {
stop := make(chan bool)
go someFunction(stop)
//很多行代码
//很多行代码
//很多行代码
stop <- true
//其他代码
//其他代码
}
在协程里面是一个10秒执行一次的定时函数。但是我们可以在外面控制这个协程,从而随时停止这个协程。