On Fri, Apr 27, 2007 at 04:57:21AM +0900, Earle Clubb wrote:
> irb(main):001:0> 0.upto(25) do
> irb(main):002:1* puts Time.now.usec/1000
> irb(main):003:1> STDOUT.flush
> irb(main):004:1> sleep 0.01
> irb(main):005:1> end
> 105
> 132
> 143

I believe part of the problem is that you are not correcting for the
time that ruby spends in the loop.  In [ruby-talk:42003] Dave Thomas
proposed this solution:

  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

Which I've tested using this code:

  n = 0
  every(0.01) do
    puts Time.now.usec / 1000
    n += 1
    break if n == 25
  end

And got this output on Linux 2.6.5:

[pbrannan@zaphod tmp]$ ruby test.rb
37
47
57
67
77
87
97
107
117
127
137
147
157
167
177
187
197
207
217
227
237
247
257
267
277

You'll still get problems if the amount of time you spend doing work in
the loop exceeds 0.01 second.

Paul