Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Timer in Ruby performance

I was looking for an online example demonstrating a timer in ruby and came across the code below. It works as expected but does it make sense that this simple program uses 30Mo of memory (as shown in windows task manager) and way too much CPU?

Thanks a lot

def time_block
  start_time = Time.now
  Thread.new { yield }
  Time.now - start_time
end

def repeat_every(seconds)
  while true do
    time_spent = time_block { yield } # To handle -ve sleep interaval
    sleep(seconds - time_spent) if time_spent < seconds
  end
end

repeat_every(5) {
}
like image 321
Elsanto Avatar asked Feb 17 '10 08:02

Elsanto


People also ask

What is the use of time in Ruby?

The Ruby Time Class. You can use the Time class in Ruby to represent a time & date. This date has three components: And time: This information is stored by the Time class as the number of seconds since the Epoch, also known as Unix time.

How do you make the timer ring until the user does something?

Also, would it be possible to make the timer ring until the user does a certain thing (such as a math problem)? Here's 3 simple steps: 1) write down current time as start time; 2) every second (or so) compare current time with start time; 3) if specified number of seconds have passed since start time, ring the bell.

How to get current time using nanoseconds in Ruby?

When Ruby uses a nanosecond-resolution clock function, such as clock_gettime of POSIX, to obtain the current time, Time#to_f can lose information of a Time object created with Time.now. Returns the value of time as an integer number of seconds since the Epoch.

Is it possible to do time Math in pure Ruby?

These methods are not available in pure Ruby, they are added by the ActiveSupport component of Rails. Here you can find some examples, notice how these methods don’t return Time or Date objects, but a custom ActiveSupport class. You can do time math with these & get things like tomorrow’s date:


1 Answers

As noted in the comments to the question, all it takes to make it work is that you join on the thread:

#!/usr/bin/ruby1.8

def repeat_every(interval, &block)
  loop do
    start_time = Time.now
    Thread.new(&block).join
    elapsed = Time.now - start_time
    sleep([interval - elapsed, 0].max)
  end
end

repeat_every(5) do
  puts Time.now.to_i
end

# => 1266437822
# => 1266437827
# => 1266437832
...

However, as it sits, there's no reason to use threads for the code in the question:

def repeat_every(interval)
  loop do
    start_time = Time.now
    yield
    elapsed = Time.now - start_time
    sleep([interval - elapsed, 0].max)
  end
end

repeat_every(5) do
  puts Time.now.to_i
end

# => 1266437911
# => 1266437916
# => 1266437921

Now, if what you want is a thread that does something at intervals, so that the main program can do something else, then you'll wrap that entire loop in a thread.

def repeat_every(interval)
  Thread.new do
    loop do
      start_time = Time.now
      yield
      elapsed = Time.now - start_time
      sleep([interval - elapsed, 0].max)
    end
  end
end

thread = repeat_every(5) do
  puts Time.now.to_i
end  
puts "Doing other stuff..."
thread.join

# => 1266438037
# => Doing other stuff...
# => 1266438042
# => 1266438047
like image 113
Wayne Conrad Avatar answered Sep 28 '22 16:09

Wayne Conrad