ping function every x amount seconds - ruby

How would I do a specific task every x amount of seconds in ruby? I've tried using Time.now.to_i for epoch then once a Time.now_i hits that task second it executes, but I have not successfuly done this, can someone show me a small example on how to execute a function every x amount of seconds?
Attempt:
def interval(timeout,function,*data)
now = Time.now.to_i
tasktime = Time.now.to_i + timeout
taskfunction = function
taskdata = data
end
I stopped the code there because I do not know how/what to do next in ruby, so what it should do for example if someone can generate a code that can do something like this example,
def say(word)
puts word
end
If you set a interval for the function would be say, the data would be the "word" then it would execute that function every x amount of seconds

If you simply sleep for a constant amount of time as suggested in other answers, the error will contaminate as it keeps running, and will not be accurate. In fact, each iteration would take longer than the given interval.
The answer shown below adjusts the lag each time per iteration.
module Kernel
def tick_every sec, &pr
Thread.new do loop do
pr.call
t = Time.now.to_f
frac = t.modulo(sec.to_f)
sleep(sec - frac)
end end
end
end
thread = tick_every(2) do
puts "foo"
end
...
some_other_tasks
...
thread.kill

You can use Kernel#sleep method for the same.
Here is the post
Ruby sleep or delay less than a second?
Tell Ruby Program to Wait some amount of time

This method would puts the word every 2 seconds endless, synchronously (means other ruby code has to wait until this execution is finished (..endless..:)).
def say(word)
while true do
t = Time.now.to_f
puts word
frac = t.modulo(2.to_f)
sleep(2 - frac)
end
end

Related

How to call a method every X seconds in Rails? [duplicate]

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?
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
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

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?
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
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

Benchmarking Ruby Code

I'm doing the following Ruby Tutorial https://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/50-debugging/lessons/124-benchmarking_ruby_code. One of the exercises asks me to:
use Ruby's super-awesome blocks to create a method which takes in a
block, executes it, and returns the time it took.
The exercise looks like this:
def benchmark
# your code here!
end
time_taken = benchmark do
sleep 0.1
end
puts "Time taken #{time_taken}"
there is a hint (Need a hint?) below the exercise:
Ruby Blocks - Introduction to Blocks in Ruby (Ruby Primer)
and i did so:
def benchmark(time)
begin_time = Time.now
end_time = Time.now
time.benchmark {|time| yield time}
end
time_taken = benchmark do
sleep 0.1
end
puts "Time taken #{time_taken}
but received an error.
i am interested in: why is local variable - 'time_taken', suggested without representing an element after 'do'? or is it not necessary? Can anyone tell me how to write code to get the positive result.
You should do it much easier:
def benchmark
begin_time = Time.now
yield
end_time = Time.now
end_time - begin_time
end
time_taken = benchmark do
sleep 0.1
end
puts "Time taken #{time_taken}"
First you collect the time and store in in variable begin_time, then yield - so run the block, then collect the end time. Return the difference. That's it.
That's pretty far off, and not really at all salvagible.
Your benchmark method should look like this pseudo code:
def benchmark
let begin_time -> current time
execute the block
let end_time -> current_time
return endtime - begintime
end
As far as executing the block being passed in, there is no time.benchmark method, I'm not sure where that came from, and you do not need to pass anything into the block. You want a single, simple yield.

how to invoke a method for every second in ruby

I wanted to create a stopwatch program in ruby so I googled it and found this SO Q.
But over there, the author calls the tick function with 1000xxx.times. I wanted to know how I can do it using something like (every second).times or for each increment of second do call the tick function.
This function:
def every_so_many_seconds(seconds)
last_tick = Time.now
loop do
sleep 0.1
if Time.now - last_tick >= seconds
last_tick += seconds
yield
end
end
end
When used like this:
every_so_many_seconds(1) do
p Time.now
end
Results in this:
# => 2012-09-20 16:43:35 -0700
# => 2012-09-20 16:43:36 -0700
# => 2012-09-20 16:43:37 -0700
The trick is to sleep for less than a second. That helps to keep you from losing ticks. Note that you cannot guarantee you'll never lose a tick. That's because the operating system cannot guarantee that your unprivileged program gets processor time when it wants it.
Therefore, make sure your clock code does not depend on the block getting called every second. For example, this would be bad:
every_so_many_seconds(1) do
#time += 1
display_time(#time)
end
This would be fine:
every_so_many_seconds(1) do
display_time(Time.now)
end
Thread.new do
while true do
puts Time.now # or call tick function
sleep 1
end
end

Is there a way to write a Ruby loop that runs one iteration for a maximum set amount of time?

I'm looking to create a Ruby (MRI 1.9.3) loop that runs at most for a certain amount of time, and once that time is up it goes to the next iteration of the loop.
For example, this is what I'm hoping to achieve:
timer = Timer.new
while foo
timer.after 5 do # The loop on foo only gets to run for 5 seconds
next
end
# Do some work here
end
So far, I've found tarcieri's gem called Timers (https://github.com/tarcieri/timers) which is what I'm trying to emulate in the code above, but my implementation doesn't give the behavior I expect, which is for the loop to go to the next iteration after 5 seconds if my work takes longer than that. Any ideas?
require 'timeout'
timeout_in_seconds = 5
while foo
begin
Timeout.timeout(timeout_in_seconds) do
# Do some work here
end
rescue Timeout::Error
next
end
end
It's been awhile since I brushed off my Ruby skills, but I believe you can do this with the timeout library.
require 'timeout'
while foo
Timeout.timeout(5) do
work()
end
end
You can also try this:
time = 60
time_start = Time.now
begin
time_running = Time.now - time_start
#You_code_goes_here
end until (time_running.to_i >= time)
That loop will happen until the time_running var is equal or greater than "60".

Resources