Friday, February 25, 2011

Fix EventMachine::PeriodicTimer

EventMachine::PeriodicTimer doesn't give an accurate timing. For example, if I add a periodic timer with 1 second interval, in my Mac, it looks like this.

1. the test code.

 require 'eventmachine'  
puts 'Start'
EM.run do
EM::add_periodic_timer 1.0 do
puts "time: #{Time.new.to_f.round(1)}"
end
end


2. output in my MacBook Pro.
 time: 1298620726.9  
time: 1298620728.0
time: 1298620729.1
time: 1298620730.1
time: 1298620731.2
time: 1298620732.3
time: 1298620733.4
time: 1298620734.5
time: 1298620735.5
time: 1298620736.6
time: 1298620737.7
time: 1298620738.8
time: 1298620739.9
time: 1298620741.0
time: 1298620742.0
time: 1298620743.1
time: 1298620744.2
time: 1298620745.3
time: 1298620746.4
time: 1298620747.4
time: 1298620748.5
time: 1298620749.6


As you can see, it drifted 100ms every time. Which is not very good when you want to do some job every 1 second. You might omit some seconds. So, with using the same method that I used for the Periodic ruby service, I made a change to PeriodicTimer. It looks like this.

 # Override PeriodicTimer  
module EventMachine
class PeriodicTimer
alias :old_initialize :initialize
def initialize interval, callback=nil, &block
# Added two additional instance variables to compensate difference.
@start = Time.now
@fixed_interval = interval
old_initialize interval, callback, &block
end
alias :old_schedule :schedule
def schedule
# print "Started at #{@start}..: "
compensation = (Time.now - @start) % @fixed_interval
@interval = @fixed_interval - compensation
# Schedule
old_schedule
end
end
end


So, here is the result (this is not that accurate like the simple ruby service, but reasonably useable.

 time: 1298620683.4  
time: 1298620684.4
time: 1298620685.4
time: 1298620686.4
time: 1298620687.4
time: 1298620688.4
time: 1298620689.4
time: 1298620690.4
time: 1298620691.3
time: 1298620692.3
time: 1298620693.4
time: 1298620694.4
time: 1298620695.4
time: 1298620696.4
time: 1298620697.4
time: 1298620698.4
time: 1298620699.4


That's it. :-)

No comments: