参考资料:
http://www.cstdlib.com/tech/2015/08/17/golang-timer/
https://yanyiwu.com/work/2014/11/08/golang-select-typical-usage.html
select
golang的select的代码形式和switch非常相似,不过select的case里面的操作语句只能是IO操作。
我觉得这句话说的非常到位,我目前的理解就是专门用来匹配channel的输出。
func main(){
tick := time.NewTicker(2*time.Second)
onhour := make(chan int,1)
if time.Now().Hour() == 9{
fmt.Println("onhour is ready to send")
onhour <- 6
fmt.Println("onhour sended")
}
for{
select {
case <- tick.C:
fmt.Println("this is 2 seconds")
case <- onhour:
fmt.Println("this is onhour")
}
}
}
这段代码的实现了一个定时器,1是定点执行(每天9点钟执行),2是定时执行(每隔2秒执行)
channel缓存
onhour1 := make(chan int,1)
onhour2:= make(chan int)
onhour1的缓存是1,也就是通道里面可以缓存1个值,往里面塞第二个值时,如果第一个值没有被读取,那么就会被阻塞。
onhour的缓存是0,也就是通道里面不可以缓存值。好比是个直肠子,有了就马上得拉出来。一旦有值进去不立即进行读取的话,就会发生阻塞。
func main(){
tick := time.NewTicker(2*time.Second)
onhour := make(chan int)
if time.Now().Hour() == 9{
fmt.Println("onhour is ready to send")
onhour <- 6
fmt.Println("onhour sended")
}
for{
select {
case <- tick.C:
fmt.Println("this is 2 seconds")
case <- onhour:
fmt.Println("this is onhour")
}
}
}
这段代码中把onhour替换成了无缓存的channel,一运行就会发现打出“onhour is ready to send”就卡住了。
每天/每小时 定时发消息。
func main(){
tick := time.NewTicker(2*time.Second)
onhour := make(chan int,1)
if time.Now().Hour() == 9{
fmt.Println("onhour is ready to send")
onhour <- 6
fmt.Println("onhour sended")
}
for{
select {
case <- tick.C:
fmt.Println("this is 2 seconds")
case <- onhour:
fmt.Println("this is onhour")
}
}
}
现在贴出来的这段代码只能实现每隔几秒钟发消息,但是不能实现每天定时发消息。因为time.Now().Hour() == 9只会被执行一次,如果想每天发消息还需要更改。
func main(){
tick := time.NewTicker(2*time.Second)
onhour := make(chan int,1)
for{
if time.Now().Second() == 9{
fmt.Println("onhour is ready to send")
onhour <- 6
fmt.Println("onhour sended")
}
}}
for{
select {
case <- tick.C:
fmt.Println("this is 2 seconds")
case <- onhour:
fmt.Println("this is onhour")
}
}
}
这么写不行,运行一下你就会发现程序卡死在第一个for循环上。所以我就想到了用go func(){}(),在我看来,go func(){}()就和nodejs里面的回调差不多,也好比游戏中开个支线任务,支线任务的执行与否对主线不会产生重大影响。
func main(){
tick := time.NewTicker(2*time.Second)
onhour := make(chan int,1)
go func(){for{
if time.Now().Second() == 9{
fmt.Println("onhour is ready to send")
onhour <- 6
fmt.Println("onhour sended")
}
}}()
for{
select {
case <- tick.C:
fmt.Println("this is 2 seconds")
case <- onhour:
fmt.Println("this is onhour")
}
}
}
我写出来后认为这就是终极版本了,没想到运行一下还是有问题。一到了每分钟的第九秒种,程序就和小兔子窜稀似的,打出一大坨东西。这是为什么呢?
原来计算机工作起来是非常快的,在1秒内,计算机能够把for循环运行很多次,这样的话,在这1秒内,第一个for循环总是成立的,所以就打出了那么多东西。因此我做了如下更改。
func main(){
tick := time.NewTicker(1*time.Second)
onhour := make(chan int,1)
go func(){
for{
if time.Now().Second() == 9 {
fmt.Println("onhour is ready to send")
onhour <- time.Now().Second()
fmt.Println("onhour sended")
time.Sleep(2*time.Second)
}
}
}()
for{
select {
case <- tick.C:
fmt.Println("this is counter",time.Now().Second())
case <- onhour:
fmt.Println("this is onhour")
}
}
}
让第一个for循环休息两秒,这样子运行后我发现确实解决了打出很多的问题。
这是我封装的一个定点器
func setTime(messager chan bool,per string,settedTime map[string]int){
go func(){
for{
var execCodition bool
now := time.Now()
dBool := now.Day() == settedTime["d"]
hBool := now.Hour() == settedTime["H"]
mBool := now.Minute() == settedTime["M"]
sBool := now.Second() == settedTime["S"]
switch per {
case "month":
execCodition = dBool && hBool && mBool && sBool
case "day":
execCodition = hBool && mBool && sBool
case "hour":
execCodition = mBool && sBool
case "minute":
execCodition = sBool
}
var execTimes string
for key,val := range settedTime{
execTimes += key
execTimes += "-"
execTimes += strconv.FormatInt(int64(val),10)
execTimes += "/"
}
msg := fmt.Sprintf("per %s %s execute",per,execTimes)
if execCodition{
messager <- true
log.Println(msg)
time.Sleep(2*time.Second)
}
}
}()
}