From: Pit Capitain Date: 2002-06-09T06:50:03+09:00 Subject: Re: 1-second events On 8 Jun 2002, at 0:58, Dave Thomas wrote: > Here's a version that corrects for the execution time of the body: > > def every(period) > base = last = Time.now.to_f > count = 0 > > loop do > now = Time.now.to_f > actual_secs = now - base > expected_secs = period * count > correction = expected_secs - actual_secs > correction = -period if correction < -period > select(nil, nil, nil, period + correction) > now = Time.now > last = now.to_f > count += 1 > yield(now) > end > end > > every(1.0) do |now| > puts "#{now.tv_sec}.#{now.tv_usec}" > > # the sleep below simuates doing some arbitrary amount of work > # that takes up to 1 second > > sleep(rand()) > end > You can get it even simpler with the original code and a method sleep_until: def sleep_until( end_time ) duration = end_time - Time.now sleep( duration ) if duration > 0 end def periodically( seconds, *args ) next_time = Time.now loop do sleeper = Thread.new { sleep_until( next_time += seconds )} yield( *args ) sleeper.join end end periodically( 1.0 ) do puts "#{Time.now.tv_sec}.#{Time.now.tv_usec}" sleep( rand * 1.3 ) end Just as Dave's code (I suppose), this should also handle work times longer than 1 second, as long as the average work time is less than one second. This is simulated by "rand * 1.3" in the code above and shown in the following sequence: 1023572512.226000 1023572513.217000 1023572514.219000 1023572515.220000 1023572516.222000 1023572517.453000 # work longer than a second 1023572518.515000 # work longer than a second 1023572519.216000 # back to normal 1023572520.217000 1023572521.219000 1023572522.220000 1023572523.222000 1023572524.223000 1023572525.225000 1023572526.226000 1023572527.217000 1023572528.259000 # work longer than a second 1023572529.220000 # back to normal 1023572530.222000 1023572531.223000 Regards, Pit