ไปไน Date๏ผParse๏ผParseInLocation๏ผๅฐฑไธ่ฏดไบใไธป่ฆๅ ณๆณจไธ้ขๅ ไธชๅฝๆฐ๏ผ
func Tick(d Duration) <-chan Time
func NewTicker(d Duration) *Ticker
func (t *Ticker) Stop()
package main
import (
"fmt"
"time"
)
func main() {
for t := range time.Tick(time.Second * 2) {
fmt.Println(t, "hello world")
}
}
package main
import (
"fmt"
"time"
)
func main() {
ticker := time.NewTicker(time.Second * 2)
for {
select {
case t := <-ticker.C:
fmt.Println(t, "hello world")
}
}
}
้่ฆๆณจๆ็ๆฏ๏ผticker ๅจไธไฝฟ็จๆถ๏ผๅบ่ฏฅๆๅจ stop๏ผๅฆๆไธ stop ๅฏ่ฝไผ้ ๆ timer ๆณ้ฒ๏ผๆฏๅฆไธ้ข่ฟๆ ท็ไปฃ็ :
package main
import (
"fmt"
"time"
)
func main() {
for {
select {
case t := <-time.Tick(time.Second * 2):
fmt.Println(t, "hello world")
}
}
}
ๆณ้ฒไนๅไผๅจๆถ้ดๅ ไธญ็ดฏ็งฏ่ถๆฅ่ถๅค็ timer ๅฏน่ฑก๏ผไป่ๅ็ๆด้บป็ฆ็้ฎ้ขใ
func After(d Duration) <-chan Time
func NewTimer(d Duration) *Timer
func (t *Timer) Reset(d Duration) bool
func (t *Timer) Stop() bool
time.After ไธ่ฌ็จๆฅๆงๅถๆไบ่ๆถ่พ้ฟ็่กไธบ๏ผๅจ่ถ ๆถๅไธๅ็ญๅพ ๏ผไปฅไฝฟ็จๅบ่กไธบๅฏ้ขๆใๅฆๆไธๅ่ถ ๆถๅๆถ้ๆพ่ตๆบ๏ผๅๅฏ่ฝๅ ไธบไพ่ตๆนๅๅบ็ผๆ ข่ๅฏผ่ดๆฌๅฐ่ตๆบๅ ็งฏ๏ผไพๅฆ fd๏ผ่ฟๆฅๆฐ๏ผๅ ๅญๅ ็จ็ญ็ญใไป่ๅฏผ่ดๆๅกๅฎๆบใ
่ฟ้็จ้ปๅก channel ่ฏปๅไผๆฐธ่ฟ้ปๅก็็นๆงๆฅๆจกๆ่พ้ฟๆถ้ด็่กไธบ๏ผๅจ่ถ ๆถๅไผไป select ไธญ่ทณๅบใ
package main
import "time"
func main() {
var ch chan int
select {
case <-time.After(time.Second):
println("time out, and end")
case <-ch:
}
}
time.After ๅ time.Tick ไธๅ๏ผๆฏไธๆฌกๆง่งฆๅ็๏ผ่งฆๅๅ timer ๆฌ่บซไผไปๆถ้ดๅ ไธญๅ ้คใๆไปฅไธ่ฌๆ
ๅตไธ็ดๆฅ็จ <-time.After
ๆฏๆฒกๆ้ฎ้ข็๏ผไธ่ฟๅจ for ๅพช็ฏ็ๆถๅ่ฆๆณจๆ:
package main
import "time"
func main() {
var ch = make(chan int)
go func() {
for {
ch <- 1
}
}()
for {
select {
case <-time.After(time.Second):
println("time out, and end")
case <-ch:
}
}
}
ไธ้ข็ไปฃ็ ๏ผ<-ch ่ฟไธช case ๆฏๆฌกๆง่ก็ๆถ้ด้ฝๅพ็ญ๏ผไฝๆฏๆฌก่ฟๅ
ฅ select๏ผtime.After
้ฝไผๅ้
ไธไธชๆฐ็ timerใๅ ๆญคไผๅจ็ญๆถ้ดๅ
ๅๅปบๅคง้็ๆ ็จ timer๏ผ่ฝ็ถๆฒก็จ็ timer ๅจ่งฆๅๅไผๆถๅคฑ๏ผไฝ่ฟ็งๅๆณไผ้ ๆๆ ๆไน็ cpu ่ตๆบๆตช่ดนใๆญฃ็กฎ็ๅๆณๅบ่ฏฅๅฏน timer ่ฟ่ก้็จ๏ผๅฆไธ:
package main
import "time"
func main() {
var ch = make(chan int)
go func() {
for {
ch <- 1
}
}()
timer := time.NewTimer(time.Second)
for {
timer.Reset(time.Second)
select {
case <-timer.C:
println("time out, and end")
case <-ch:
}
}
}
ๅ Ticker ไธๆ ท๏ผๅฆๆไนๅ็ timer ๆฒก็จไบ๏ผๅฏไปฅๆๅจ Stop ไปฅไฝฟ่ฏฅ timer ไปๆถ้ดๅ ไธญ็งป้คใ
โโโโโโโโโโ
โ timers โ
โโโโโโฌโโโโดโฌโโโโโฌโโโโโฌโโโโโฌโโโโโฌโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโ
โ โ โ โ โ โ โ โ โ โ
โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ ... โ 63 โ
โโโโโโดโโโโโดโโโโโดโโโโโดโโโโโดโโโโโดโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโ
โ โ
โ โ
โ โ
โ โ
โ โ
โ โ โ โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโ โ โ โ โโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโถ โ cacheline size โ โโโโโโโโโโค โ โโโโโโโโโโถ โ cacheline size โ โโโโโโโโโโค
โ โ โโโโโโโโโโโโโโโโโโโโโโ โ โ โ โโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโค โ โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโค
โโถโtimersBucket โ โ โ โโโโโถโtimersBucket โ โ โ
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโค pad โ โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโค pad โ
โ lock mutex โ โ โ lock mutex โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ gp *g โ โ โ gp *g โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ created bool โ โ โ created bool โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ ........ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ sleeping bool โ โ โ sleeping bool โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ rescheduling bool โ โ โ rescheduling bool โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ sleepUntil int64 โ โ โ sleepUntil int64 โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ waitnote note โ โ โ waitnote note โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ t []*timer โ โ โ t []*timer โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโ
โ
โ
โ
โผ
โโโโโ
โ 0 โ
โโโโโ
โ
โ
โ
โ
โผ
โโโโโฌโโโโฌโโโโฌโโโโ
โ 1 โ 2 โ 3 โ 4 โ
โโโฌโโดโโฌโโดโโฌโโดโโฌโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โโโโโโโโ โโโโโโโโโโ โ
โผ โ โ โผ
โโโโโฌโโโโฌโโโโฌโโโโ โผ โผ โโโโโฌโโโโฌโโโโฌโโโโ
โ โ โ โ โ โโโโโฌโโโโฌโโโโฌโโโโ โโโโโฌโโโโฌโโโโฌโโโโ โ โ โ โ โ
โโโฌโโดโโฌโโดโโโโดโโโโ โ โ โ โ โ โ โ โ โ โ โโโโโดโโโโดโโฌโโดโโฌโโ
โ โ โโโโโดโโโโดโโโโดโโโโ โโโโโดโโโโดโโโโดโโโโ โ โ
โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโ
โ โ โ โ
โ โ โ โ
โผ โผ โผ โผ
โโโโโฌโโโโฌโโโโฌโโโโ โโโโโฌโโโโฌโโโโฌโโโโ โโโโโฌโโโโฌโโโโฌโโโโ โโโโโฌโโโโฌโโโโฌโโโโ
โ โ โ โ โ โ โ โ โ โ ................. โ โ โ โ โ โ โ โ โ โ
โโโโโดโโโโดโโโโดโโโโ โโโโโดโโโโดโโโโดโโโโ โโโโโดโโโโดโโโโดโโโโ โโโโโดโโโโดโโโโดโโโโ
ไธ้ข็็ป่ฎบ้ฝๅฏไปฅ็ปๅไธ้ข็ๅพๆฅ็ใ
ๅจ runtime/time.go
ไธญๅฎไนไบ timers ๆฐ็ป:
var timers [timersLen]struct {
timersBucket
pad [sys.CacheLineSize - unsafe.Sizeof(timersBucket{})%sys.CacheLineSize]byte
}
ๅจ Go ็ๆฉๆๅฎ็ฐไธญๆฏๅ จๅฑไธไธช timer ็๏ผไฝๆไฝๅ จๅฑ็ timer ๅ ่ฆๅ ้๏ผๆไปฅๅคๆ ธๅฟไผๆด้ฒๅบๅ ไธบไบ้่ๆง่ฝไฝไธ็้ฎ้ขใไปๆไธช็ๆฌ(ๅฏ๏ผๆไนไธ็ฅ้ๅชไธช๏ผๅคงๆฆๆฏ 1.10)่ตท๏ผGo ็ timers ไฟฎๆนๆไบ่ฟ็งๅคไธชๆถ้ดๅ ็ๅฎ็ฐๆนๅผ๏ผ็ฎๅๅจ runtime ้ๅๆญปไธบ 64:
const timersLen = 64
ๅฏ๏ผๅฎๆน่กจ็คบๅฆๆๅ GOMAXPROCS ็ธ็ญ็่ฏ๏ผ้ฃไนไผๅจ procresize ็ๆถๅ้ๆฐๅ้ ๅไฟฎๆน่ฟไบๆถ้ดๅ ใๅๆญปๆ 64 ๆฏๅ ๅญไฝฟ็จๅๆง่ฝไธ็ไธไธชๆ่กทใๅฆๆ GOMAXPROCS ๆฏ 64 ๅคง็่ฏ๏ผ้ฃไนๅฏ่ฝๅคไธช P ไผๅ ฌ็จๅไธไธชๆถ้ดๅ ใๅฝ็ถ๏ผๅฎ้ ๅบๆฏไธญๆ่ฟๆฒกๆ่ง่ฟ 64 ๆ ธไปฅไธ็ CPUใ
timers ๆฐ็ป็ๅ ็ด ๆฏไธไธชๅฟๅ struct๏ผๅ ๅซ timersBucket ๅ pad ไธคไธชๆๅ๏ผ่ฟไธช pad ๆฏไธบไบๅกซๅ struct ๅฐ cacheline ็ๆดๆฐๅ๏ผไปฅ้ฟๅ ๅจไธๅ็ P ไน้ดๅ็ false sharingใๅจๅคๆ ธๅฟ็็ผ็จๅบๆฏไธญ่พไธบๅธธ่งใtimerBucket ็็ปๆ:
//go:notinheap
type timersBucket struct {
lock mutex
gp *g
created bool
sleeping bool
rescheduling bool
sleepUntil int64
waitnote note
t []*timer
}
ๅ
ถไธญ็ t ๅฐฑๆฏๆไปฌ็ๆถ้ดๅ ไบ๏ผไธ่ฟ่ฟไธชๅๆไปฌไผ ็ป็ heap ็ปๆ็จๅพฎๆๆไธๅ๏ผๆฏๅๅไธชๅ็๏ผ่ฟ็ง่ฎพ่ฎก็ฌฌไธๆฌก่งใ่ฟ้็ timersBucket ่ฟๆไธช็นๆฎ็ๆณจ้ go:notinheap
๏ผๅฎๆน็่ฏดๆ:
go:notinheap applies to type declarations. It indicates that a type must never be allocated from the GC'd heap. Specifically, pointers to this type must always fail the runtime.inheap check. The type may be used for global variables, for stack variables, or for objects in unmanaged memory (e.g., allocated with sysAlloc, persistentalloc, fixalloc, or from a manually-managed span). Specifically:
- new(T), make([]T), append([]T, ...) and implicit heap allocation of T are disallowed. (Though implicit allocations are disallowed in the runtime anyway.)
- A pointer to a regular type (other than unsafe.Pointer) cannot be converted to a pointer to a go:notinheap type, even if they have the same underlying type.
- Any type that contains a go:notinheap type is itself go:notinheap. Structs and arrays are go:notinheap if their elements are. Maps and channels of go:notinheap types are disallowed. To keep things explicit, any type declaration where the type is implicitly go:notinheap must be explicitly marked go:notinheap as well.
- Write barriers on pointers to go:notinheap types can be omitted. The last point is the real benefit of go:notinheap. The runtime uses it for low-level internal structures to avoid memory barriers in the scheduler and the memory allocator where they are illegal or simply inefficient. This mechanism is reasonably safe and does not compromise the readability of the runtime.
ๅฏ๏ผไบ่งฃไธไธๅฐฑ่กไบ๏ผๅจ็จๆทไปฃ็ ไธญๅบๆฌไธไผ็จๅพๅฐใ
ๅๅๅ ้ซๅบฆไธๆฏไบๅๅ ่ฆ็ฎไธไบใไธไธช่็น็ๆๆ(ๆๅคๆ4ไธช)ๅญฉๅญ่็น้ฝๆฏ่ฟไธช่็น่ฆๅคงใไธไธช่็น็(ๅชๆไธไธช)็ถ่็นไธๅฎๆฏๅฝๅ่็นๅฐใไธ้ขๆฏๅกซๅฅฝๅผไนๅ็ไธไธชๅ ธๅ็ๅๅๅ :
โโโโโโโ
โ โ
โ 0 โ
โโโโโโโ
โ
โ
โ
โผ
โโโโโโโฌโโโโโโฌโโโโโโฌโโโโโโ
โ โ โ โ โ
โ 3 โ 2 โ 2 โ 10 โ
โโโโโโโดโโโโโโดโโโโโโดโโโโโโ
โ โ โ โ
โ โ โ โ
โโโโโโโโโโโโ โ โ โ โ
โโโโโโโโโโโโโโโโโโค 4*i+1 โโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโ โโโโโ โ
โ โ โ โ
โ โ โ โ
โผ โ โ โผ
โโโโโโโฌโโโโโโฌโโโโโโฌโโโโโโ โ โ โโโโโโโฌโโโโโโฌโโโโโโฌโโโโโโ
โ โ โ โ โ โผ โผ โ โ โ โ โ
โ 20 โ 4 โ 5 โ 13 โ โโโโโโโฌโโโโโโฌโโโโโโฌโโโโโโ โโโโโโโฌโโโโโโฌโโโโโโฌโโโโโโ โ 99 โ 13 โ 11 โ 12 โ
โโโโโโโดโโโโโโดโโโโโโดโโโโโโ โ โ โ โ โ โ โ โ โ โ โโโโโโโดโโโโโโดโโโโโโดโโโโโโ
โ 12 โ 14 โ 15 โ 16 โ โ 3 โ 10 โ 3 โ 3 โ
โโโโโโโดโโโโโโดโโโโโโดโโโโโโ โโโโโโโดโโโโโโดโโโโโโดโโโโโโ
ๅไบๅๅ ไธๆ ท๏ผๅฏนไบไธไธช่็น็่ฆๆฑๅชๆๅๅ ถ็ถ่็นไปฅๅๅญ่็นไน้ด็ๅคงๅฐๅ ณ็ณปใ็ธ้ป่็นไน้ดๆฒกๆไปปไฝๅ ณ็ณปใ
// ๅ้
timerBucket
// ๅ ้๏ผๆทปๅ timer ่ฟๆถ้ดๅ
func addtimer(t *timer) {
tb := t.assignBucket()
lock(&tb.lock)
tb.addtimerLocked(t)
unlock(&tb.lock)
}
// ๅคช็ฎๅไบ๏ผๅฐฑๆฏ็จ g.m.p ็ id ๆจก 64
// ็ถๅๅ้
ๅฏนๅบ็ timerBucket
func (t *timer) assignBucket() *timersBucket {
id := uint8(getg().m.p.ptr().id) % timersLen
t.tb = &timers[id].timersBucket
return t.tb
}
// ๅๆถ้ดๅ ไธญๆทปๅ ไธไธช timer๏ผๅฆๆๆถ้ดๅ ็ฌฌไธๆฌก่ขซๅๅงๅๆ่
ๅฝๅ็ timer ๆฏไนๅๆๆ็ timers ้ฝ่ฆๆฉ๏ผ้ฃไนๅฐฑๅฏๅจ(้ฆๆฌกๅๅงๅ)ๆๅค้(ๆๆฉ็ timer) timerproc
// ๅฝๆฐๅ
ๅ่ฎพๅค้จๅทฒ็ปๅฏน timers ๆฐ็ปๅ ้ไบ
func (tb *timersBucket) addtimerLocked(t *timer) {
// when ๅฟ
้กปๅคงไบ 0๏ผๅฆๅไผๅจ่ฎก็ฎ delta ็ๆถๅๆบขๅบๅนถๅฏผ่ดๅ
ถๅฎ็ runtime timer ๆฐธ่ฟๆฒกๆณ่ฟๆ
if t.when < 0 {
t.when = 1<<63 - 1
}
t.i = len(tb.t)
tb.t = append(tb.t, t)
siftupTimer(tb.t, t.i)
if t.i == 0 {
// ๆฐๆๅ
ฅ็ timer ๆฏไนๅๆๆ็้ฝ่ฆๆฉ
// ๅไธ่ฐๆดๅ
if tb.sleeping {
// ไฟฎๆน timerBucket ็ sleep ็ถๆ
tb.sleeping = false
// ๅค้ timerproc
// ไฝฟ timerproc ไธญ็ for ๅพช็ฏไธๅ้ปๅกๅจ notesleepg ไธ
notewakeup(&tb.waitnote)
}
// ๅไธไธช P ไธ็ๆๆ timers ๅฆๆ
// ้ฝๅจ timerproc ไธญ่ขซๅผนๅบไบ
// ่ฏฅ rescheduling ไผ่ขซๆ ่ฎฐไธบ true
// ๅนถไธๅฏๅจ timerproc ็ goroutine ไผ่ขซ goparkunlock
if tb.rescheduling {
// ่ฏฅๆ ่ฎฐไผๅจ่ฟ้ๅ timejumpLocked ไธญ่ขซ่ฎพ็ฝฎไธบ false
tb.rescheduling = false
goready(tb.gp, 0)
}
}
// ๅฆๆ timerBucket ๆฏ็ฌฌไธๆฌกๅๅปบ๏ผ้่ฆๅฏๅจไธไธช goroutine
// ๆฅๅพช็ฏๅผนๅบๆถ้ดๅ ๏ผๅ
้จไผๆ นๆฎ้่ฆๆๆฉ่งฆๅ็ timer
// ่ฟ่ก็ธๅบๆถ้ด็ sleep
if !tb.created {
tb.created = true
go timerproc(tb)
}
}
ๆๅ ฅ timer ๅฐๅ ไธญ็ๆถๅ็้ป่พๆฏๅ ่ฟฝๅ ๅฐๆฐ็ปๆซๅฐพ(append)๏ผ็ถๅๅไธ adjust(siftup) heap ไปฅ้ๆฐๆขๅคๅๅๅฐ้กถๅ ๆง่ดจใ
// ไปๅ ไธญๅ ้ค timer t
// ๅฆๆ timerproc ๆๅ่ขซๅค้ไนๆฒกๆ่ฐ
func deltimer(t *timer) bool {
if t.tb == nil {
// t.tb can be nil if the user created a timer
// directly, without invoking startTimer e.g
// time.Ticker{C: c}
// In this case, return early without any deletion.
// See Issue 21874.
return false
}
tb := t.tb
lock(&tb.lock)
// t may not be registered anymore and may have
// a bogus i (typically 0, if generated by Go).
// Verify it before proceeding.
i := t.i
last := len(tb.t) - 1
if i < 0 || i > last || tb.t[i] != t {
unlock(&tb.lock)
return false
}
// ๆ timer[i] ๆฟๆขไธบ timer[last]
if i != last {
tb.t[i] = tb.t[last]
tb.t[i].i = i
}
// ๅ ้ค timer[last]๏ผๅนถ็ผฉๅฐ slice
tb.t[last] = nil
tb.t = tb.t[:last]
// ๅคๆญๆฏไธๆฏๅ ็ๆๅไธไธช
// ๅฆๆไธๆฏ็่ฏ๏ผ้่ฆ้ๆฐ่ฐๆดๅ
if i != last {
// ๆๅไธไธช่็นๅฝๅๆฅ็ๅๅๅฏ่ฝๅนถไธๆฏๅฎ้ฃไธชๅๅ
// ๆไปฅๅไธ่ตฐๆ่
ๅไธ่ตฐ้ฝๆฏๆๅฏ่ฝ็
// ๅณไฝฟๆฏไบๅๅ ๏ผไนๆฏๆ่ฟ็งๅฏ่ฝ็
siftupTimer(tb.t, i)
siftdownTimer(tb.t, i)
}
unlock(&tb.lock)
return true
}
// timerproc ่ด่ดฃๅค็ๆถ้ด้ฉฑๅจ็ไบไปถ
// ๅจๅ ไธญ็ไธไธไธชไบไปถ้่ฆ่งฆๅไนๅ๏ผไผไธ็ดไฟๆ sleep ็ถๆ
// ๅฆๆ addtimer ๆๅ
ฅไบไธไธชๆดๆฉ็ไบไปถ๏ผไผๆๅๅค้ timerproc
func timerproc(tb *timersBucket) {
tb.gp = getg()
for {
// timerBucket ็ๅฑ้จๅคง้
lock(&tb.lock)
// ่ขซๅค้๏ผๆไปฅไฟฎๆน sleeping ็ถๆไธบ false
tb.sleeping = false
// ่ฎกๆถ
now := nanotime()
delta := int64(-1)
// ๅจๅค็ๅฎๅฐๆ็ timer ไนๅ๏ผไธ็ดๅพช็ฏ
for {
// ๅฆๆ timer ๅทฒ็ป้ฝๅผนๅบไบ
// ้ฃไนไธ็จๅพช็ฏไบ๏ผ่ทณๅบๅๆฅ็็ก่ง
if len(tb.t) == 0 {
delta = -1
break
}
// ๅๅฐ้กถๅ ้กถ้จๅ
็ด
// ๅณๆ่ฟไผ่ขซ่งฆๅ็ timer
t := tb.t[0]
delta = t.when - now // ่ฟๅทฎๅค้ฟๆถ้ดๆ้่ฆ่งฆๅๆ่ฟ็ timer
if delta > 0 {
// ๅคงไบ 0 ่ฏดๆ่ฟไธช timer ่ฟๆฒกๅฐ้่ฆ่งฆๅ็ๆถ้ด
// ่ทณๅบๅพช็ฏๅป็ก่ง
break
}
if t.period > 0 {
// ่ฟไธช timer ่ฟไผ็ๅจๅ ้
// ไธ่ฟ่ฆ่ฐๆดๅฎ็ไธๆฌก่งฆๅๆถ้ด
t.when += t.period * (1 + -delta/t.period)
siftdownTimer(tb.t, 0)
} else {
// ไปๅ ไธญ็งป้ค่ฟไธช timer
// ็จๆๅไธไธช timer ่ฆ็็ฌฌ 0 ไธช timer
// ็ถๅๅไธ่ฐๆดๅ
last := len(tb.t) - 1
if last > 0 {
tb.t[0] = tb.t[last]
tb.t[0].i = 0
}
tb.t[last] = nil
tb.t = tb.t[:last]
if last > 0 {
siftdownTimer(tb.t, 0)
}
t.i = -1 // ๆ ่ฎฐ timer ๅจๅ ไธญ็ไฝ็ฝฎๅทฒ็ปๆฒกๆไบ
}
// timer ่งฆๅๆถ้่ฆ่ฐ็จ็ๅฝๆฐ
f := t.f
arg := t.arg
seq := t.seq
unlock(&tb.lock)
// ่ฐ็จ้่งฆๅ็ๅฝๆฐ
f(arg, seq)
// ๆ้ๅ ๅๆฅ๏ผๅฆๆไธๆฌก break ไบๅ
ๅฑ็ for ๅพช็ฏ
// ่ฝไฟ่ฏ timeBucket ๆฏ่ขซ้ไฝ็
// ็ถๅๅจไธ้ข็ goparkunlock ไธญ่ขซ่งฃ้
lock(&tb.lock)
}
if delta < 0 || faketime > 0 {
// ่ฏดๆๆถ้ดๅ ้ๅทฒ็ปๆฒกๆ timer ไบ
// ่ฎฉ goroutine ๆ่ตท๏ผๅป็ก่ง
tb.rescheduling = true
goparkunlock(&tb.lock, "timer goroutine (idle)", traceEvGoBlock, 1)
continue
}
// ่ฏดๆๅ ้่ณๅฐ่ฟๆไธไธชไปฅไธ็ timer
// ็กๅฐๆ่ฟ็ timer ๆถ้ด
tb.sleeping = true
tb.sleepUntil = now + delta
noteclear(&tb.waitnote)
unlock(&tb.lock)
// ๅ
้จๆฏ futex sleep
// ๆถ้ด็กๅฐไบไผ่ชๅจ้
// ๆ่
addtimer ็ๆถๅ๏ผๅ็ฐๆฐ็ timer ๆดๆฉ๏ผไผๆๅๅค้
notetsleepg(&tb.waitnote, delta)
}
}
ๅฏไปฅ็ๆไธไธ่ฟ้็ period๏ผๆ period ็ timer ไผไป when ๅผๅง๏ผๆฏ้ period ๆฎตๆถ้ด๏ผๅฐฑๅๆฌก่งฆๅใ
when+period
when+period*3
โ
โ โ
โ โ
โ when+period*2โ
when โ โ
โ โ โ
โ โ โ โ .....
โ โ โ โ
โโโโโโโโโโโโโ โ โ โ โ
โ timeline โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโผโโโโโโโโผโโโโโโโโผโโโโโโโโโโโโโโโโโโท
โโโโโโโโโโโโโ โ โ โ โ
โผ โผ โผ โผ
trigger trigger
trigger trigger
ไนๅ็ไปฃ็ ไน็ๅฐไบ๏ผๆถ้ดๅ ่ฐๆดๆๅไธ่ฐๆดๅๅไธ่ฐๆดไธค็ง่ฐๆดๆนๅผใ
func siftupTimer(t []*timer, i int) {
// ๅ
ๆๅญๅฝๅๅๆๅ
ฅๅฐๆฐ็ปๅฐพ้จ็่็น
when := t[i].when
tmp := t[i]
// ไปๅฝๅๆๅ
ฅ่็น็็ถ่็นๅผๅง
// ๅฆๆๆๆฐๆๅ
ฅ็้ฃไธช่็น็่งฆๅๆถ้ด่ฆๆฏ็ถ่็น็่งฆๅๆถ้ดๆดๆฉ
// ้ฃไนๅฐฑๆ่ฟไธช็ถ่็นไธ็งป
for i > 0 {
p := (i - 1) / 4 // parent
if when >= t[p].when {
break
}
t[i] = t[p]
t[i].i = i
i = p
}
// ๅฆๆๅ็่ฟ็งปๅจ๏ผ็จๆๆฐๆๅ
ฅ็่็น
// ่ฆ็ๆๆๅไธไธชไธ็งป็็ถ่็น
if tmp != t[i] {
t[i] = tmp
t[i].i = i
}
}
func siftdownTimer(t []*timer, i int) {
n := len(t)
when := t[i].when
tmp := t[i]
for {
c := i*4 + 1 // ๆๅทฆๅญฉๅญ่็น
c3 := c + 2 // ็ฌฌไธไธชๅญฉๅญ่็น
if c >= n {
break
}
w := t[c].when
if c+1 < n && t[c+1].when < w {
w = t[c+1].when
c++
}
if c3 < n {
w3 := t[c3].when
if c3+1 < n && t[c3+1].when < w3 {
w3 = t[c3+1].when
c3++
}
if w3 < w {
w = w3
c = c3
}
}
if w >= when {
break
}
t[i] = t[c]
t[i].i = i
i = c
}
if tmp != t[i] {
t[i] = tmp
t[i].i = i
}
}
่ฟๆฎตไปฃ็ ๅฎๅจๆฏ็งฐไธไธไผ้ ๏ผๅ ถๅฎๅฐฑๆฏๅจๆๆๅญฉๅญ่็นไธญๅ ๆพๅบๆๅฐ็้ฃไธไธช๏ผๅฆๆๆๅฐ็ๆฏๅฝๅ่ฆไธ็งป็่็น่ฟ่ฆๅคง๏ผ้ฃไนๅฐฑ breakใๅไน๏ผๅๅฐๆๅฐ็่็นไธ็งป๏ผ็ถๅๅๅคๆญ่ฟไธชๆๅฐ่็น็ 4 ไธชๅญ่็นๆฏๅฆ้ฝๆฏ่ฆไธ็งป็่็นๅคงใไปฅๆญค็ฑปๆจใ็จๅพๆฅๆจกๆไธไธ่ฟไธช่ฟ็จ:
โ โโโโโ
โ โ 5 โ
โ โโโโโ
โ โ
โ โโโโโโโ
โ โผ
โ โโโโโฌโโโโณโโโโณโโโโ
โ โ 7 โ 3 โ 2 โ 6 โ
โ โโโโโดโโโโปโโโโปโโโโ
โโโโโโโโโโโโโโโโโโโโโ โ โ
โ siftdownTimer โ โ โโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโ โ โผ
.โโโโโโโโโ. โ โโโโโฌโโโโฌโโโโณโโโโ
( before ) โ โ 4 โ 5 โ 9 โ 3 โ
`โโโโโโโโโ' โ โโโโโดโโโโดโโโโปโโโโ
โ โ
โ โโโโโโโโโโโโโโโ
โ โผ
โ โโโโโฌโโโโฌโโโโณโโโโ
โ โ 6 โ 6 โ 6 โ 4 โ
โ โโโโโดโโโโดโโโโปโโโโ
โ
โผ
โ โโโโโ
โ โ 2 โ
โ โโโโโ
โ โ
โ โโโโโโโ
โ โผ
โ โโโโโฌโโโโณโโโโณโโโโ
โ โ 7 โ 3 โ 3 โ 6 โ
โ โโโโโดโโโโปโโโโปโโโโ
โโโโโโโโโโโโโโโโโโโโโ โ โ
โ siftdownTimer โ โ โโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโ โ โผ
.โโโโโโโโโ. โ โโโโโฌโโโโฌโโโโณโโโโ
( after ) โ โ 4 โ 5 โ 9 โ 4 โ
`โโโโโโโโโ' โ โโโโโดโโโโดโโโโปโโโโ
โ โ
โ โโโโโโโโโโโโโโโ
โ โผ
โ โโโโโฌโโโโฌโโโโณโโโโ
โ โ 6 โ 6 โ 6 โ 5 โ
โ โโโโโดโโโโดโโโโปโโโโ
โ
โผ
func After(d Duration) <-chan Time {
return NewTimer(d).C
}
// NewTimer creates a new Timer that will send
// the current time on its channel after at least duration d.
func NewTimer(d Duration) *Timer {
c := make(chan Time, 1)
t := &Timer{
C: c,
r: runtimeTimer{
when: when(d),
f: sendTime,
arg: c,
},
}
startTimer(&t.r)
return t
}
func startTimer(*runtimeTimer)
่ฟไธช startTimer ็ๅฎ็ฐๆฏๅจ runtime/time.go
้:
// startTimer adds t to the timer heap.
// ๆ t ๆทปๅ ๅฐ timer ๅ
//go:linkname startTimer time.startTimer
func startTimer(t *timer) {
addtimer(t)
}
addtimer ๅ้ข็ๆต็จไนๅๅทฒ็ป็่ฟไบใ
func Tick(d Duration) <-chan Time {
if d <= 0 {
return nil
}
return NewTicker(d).C
}
// NewTicker ไผ่ฟๅไธไธช Ticker ๅฏน่ฑก๏ผๅ
ถ channel ๆฏ้ period ๆถ้ด
// ไผๆถๅฐไธไธชๆถ้ดๅผ
// ๅฆๆ receiver ๆฅๆถๆ
ขไบ๏ผTicker ไผๆไธ้่ฆ็ tick drop ๆ
// d ๅฟ
้กปๆฏ 0 ๅคง๏ผๅฆๅ panic
// Stop ticker ๆ่ฝ้ๆพ็ธๅ
ณ็่ตๆบ
func NewTicker(d Duration) *Ticker {
if d <= 0 {
panic(errors.New("non-positive interval for NewTicker"))
}
c := make(chan Time, 1)
t := &Ticker{
C: c,
r: runtimeTimer{
when: when(d),
period: int64(d),
f: sendTime,
arg: c,
},
}
startTimer(&t.r)
return t
}
ๅฏไปฅ็ๅฐ๏ผ Ticker ๅ Timer ็ r ๆๅๅฐฑๅชๅทฎๅจ period ่ฟไธไธชๅญๆฎตไธ๏ผๆฏ้ไธไธช period ๅฐฑๅพ channel ้ๅๆฐๆฎ็ๅฐฑๆฏ Ticker๏ผ่ fire and disappear ็ๅฐฑๆฏ Timerใ
func (t *Ticker) Stop() {
stopTimer(&t.r)
}
func (t *Timer) Stop() bool {
if t.r.f == nil {
panic("time: Stop called on uninitialized Timer")
}
return stopTimer(&t.r)
}
Timer ๅ Ticker ้ฝๆฏ่ฐ็จ็ stopTimerใ
func stopTimer(t *timer) bool {
return deltimer(t)
}
deltimer ๅจไธ้ขไน็ๅฐ่ฟไบใ
func (t *Timer) Reset(d Duration) bool {
if t.r.f == nil {
panic("time: Reset called on uninitialized Timer")
}
w := when(d)
active := stopTimer(&t.r)
t.r.when = w
startTimer(&t.r)
return active
}
้ฝๆฏ่ง่ฟ็ๅฝๆฐ๏ผๆฒกๅฅ็นๅซ็ใ
ๆฌ็ฏๅ ๅฎนไธป่ฆๆฏ่ฎฒ Go ็ๅฎๆถๅจๅฎ็ฐ๏ผๅทฅไธ็็ๅฎๆถๅจๅฎ็ฐๅนถไธๅชๆไธ็งใๅฆๆไฝ ่ฟๆณ็ฅ้ๅ ถๅฎ็ณป็ป๏ผๆฏๅฆ nginx ้ๆฏๆไนๅฎ็ฐๅฎๆถๅจ็๏ผๅฏไปฅๅ่่ฟไธ็ฏใ