go-zero
go-zero copied to clipboard
How does go-zero avoid pseudo-random selection in timingwheel?
func (tw *TimingWheel) run() {
for {
select {
case <-tw.ticker.Chan():
tw.onTick()
case task := <-tw.setChannel:
tw.setTask(&task)
case key := <-tw.removeChannel:
tw.removeTask(key)
case task := <-tw.moveChannel:
tw.moveTask(task)
case fn := <-tw.drainChannel:
tw.drainAll(fn)
case <-tw.stopChannel:
tw.ticker.Stop()
return
}
}
}
If more than one channel can proceed, won't code above conflict? Note the following scenarios:
- If user set small tick like 100ms or smaller at beginning for each slot, and user set a new task when tick on, if setChannel is selected, it's ok although current slot's tasks will be delayed for 100ms or less, but what if ticker.Chan is selected, new task disappears.
- It's also a big problem that if stopChannel is ignored.
- Futhermore, in extreme cases, a large duration suck as one minute like _test.go, some tasks will be delayed for so much time
I try to change this function like below:
func (tw *TimingWheel) run() {
for {
select {
case <-tw.stopChannel:
tw.ticker.Stop()
return
default:
}
select {
case <-tw.ticker.Chan():
tw.onTick()
default:
}
select {
case task := <-tw.setChannel:
tw.setTask(&task)
case key := <-tw.removeChannel:
tw.removeTask(key)
case task := <-tw.moveChannel:
tw.moveTask(task)
case fn := <-tw.drainChannel:
tw.drainAll(fn)
default:
}
}
}
It doesn't work well if test entire file, but it's passed all tests seperatelly. Are there some shared variables? Or I made a mistake.
Hope for you reply.
Reference: https://stackoverflow.com/questions/47645808/how-does-select-work-when-multiple-channels-are-involved https://stackoverflow.com/questions/46200343/force-priority-of-go-select-statement/46202533#46202533