time.After
在go中使用select时用time定义定时器的时候遇到的一个小问题,记录下
先说要求:
-
在控制台打印0-29的数字, 每隔1s打印一个
-
打印完成后, sleep10s, 然后打印"结束了", 退出程序
再看下面两份代码
A:
package main
import (
"fmt"
"time"
)
func main() {
// 定义channel
C := make(chan int64, 10)
// 使用一个goroutine每隔1s向C中send一个数
go func() {
// goroutine退出关闭C
defer close(C)
var i int64
for i = 0; i < 30; i++ {
C <- i
time.Sleep(time.Second * 1)
}
}()
// 循环receive C 中的数,并作超时处理
for {
select {
case i := <-C:
fmt.Println("num: ", i)
case <- time.After(time.Second * 10): // 注意点, 就是这里
fmt.Println("结束了")
return
}
}
}
B:
package main
import (
"fmt"
"time"
)
func main() {
// 定义channel
C := make(chan int64, 10)
// 使用一个goroutine每隔1s向C中send一个数
go func() {
// goroutine退出关闭C
defer close(C)
var i int64
for i = 0; i < 30; i++ {
C <- i
time.Sleep(time.Second * 1)
}
}()
// 定义一个定时器
timer := time.After(time.Second * 10)
// 循环receive C 中的数,并作超时处理
for {
select {
case i := <-C:
fmt.Println("num: ", i)
cacase <- timer: // 注意点, 就是这里
fmt.Println("结束了")
return
}
}
}
具体执行结果如下:
A:
PS F:\CZproject\spiderman\test_go> go run "f:\CZproject\spiderman\test_go\main\main.go"
num: 0
num: 1
num: 2
num: 3
num: 4
num: 5
num: 6
num: 7
num: 8
num: 9
num: 10
num: 11
num: 12
num: 13
num: 14
num: 15
num: 16
num: 17
num: 18
num: 19
num: 20
num: 21
num: 22
num: 23
num: 24
num: 25
num: 26
num: 27
num: 28
num: 29
结束了
B:
PS F:\CZproject\spiderman\test_go> go run "f:\CZproject\spiderman\test_go\main\main.go"
num: 0
num: 1
num: 2
num: 3
num: 4
num: 5
num: 6
num: 7
num: 8
num: 9
结束了
比较会发现第二份打印输出内容比第一份少了许多, 并不满足我们提的需求.
为什么呢?
关键点就在于定时器的声名节点以及执行节点,就是定时器在何时定义, 以及在什么时候开始计时
到了这里, 聪明的小伙伴就明白了, 第二份代码中定时器开始计时的时间节点出问题了
没错, 就是这样, 在第二份代码中, 在执行"timer := time.After(time.Second * 10)"的时候,定义定时器timer, 但在这个时候,注意了, 这个时候定时器已经开始计时了, 当过了10s后, 在执行"case <- timer", 发现已经超时了, 那么就结束吧 再来看第一份代码, 这里是在"case <- time.After(time.Second * 10)"定义定时器并开始计时, 但是注意了,这里时每执行到这一行代码时, 都会定义一个定时器并开始计时 .
就好比有两个员工A和B, 假如两个员工的忍耐极限都是10s, 现在给每个人都分配了30项工作,
A: 耐心好, 只要不是让连续干10s, 那我就能一致干下去
B: 耐心差, 我都干了10s了, 不干了, 走人...
今天就到这里了, 可爱的小伙伴别忘了点赞!!!