Salviati
Salviati

Reputation: 788

How to put a delay on a loop in Ruby?

For example, if I want to make a timer, how do I make a delay in the loop so it counts in seconds and do not just loop through it in a millisecond?

Upvotes: 17

Views: 30907

Answers (2)

sawa
sawa

Reputation: 168101

Somehow, many people think that putting a sleep method with a constant time interval as its argument will work. However, note that no method takes zero time. If you put sleep(1) within a loop, the cycle will surely be more than 1 second as long as you have some other content in the loop. What is worse, it does not always take the same time processing each iteration of a loop. Each cycle will take more than 1 second, with the error being random. As the loop keeps running, this error will contaminate and grow always toward positive. Especially if you want a timer, where the cycle is important, you do not want to do that.

The correct way to loop with constant specified time interval is to do it like this:

loop do
  t = Time.now
    #... content of the loop
  sleep(t + 1 - Time.now)
end

Upvotes: 15

Phrogz
Phrogz

Reputation: 303234

The 'comment' above is your answer, given the very simple direct question you have asked:

1.upto(5) do |n|
  puts n
  sleep 1 # second
end

It may be that you want to run a method periodically, without blocking the rest of your code. In this case, you want to use a Thread (and possibly create a mutex to ensure that two pieces of code are not attempting to modify the same data structure at the same time):

require 'thread'

items = []
one_at_a_time = Mutex.new

# Show the values every 5 seconds
Thread.new do
  loop do
    one_at_a_time.synchronize do
      puts "Items are now: #{items.inspect}"
      sleep 5
    end
  end
end

1000.times do
  one_at_a_time.synchronize do
    new_items = fetch_items_from_web
    a.concat( new_items )
  end
end

Upvotes: 32

Related Questions