1

I have an algorithm that can potentially run for an unbounded period of time, updating results as it goes. It's using something similar to an Iterative Deepening Search. After a specified amount of time, I'd like the algorithm to stop so I can use the result it has been calculating.

Here's an example of how I'm accomplishing this using threads:

best_result = 0
thread = Thread.new {
  while true
    new_result = rand
    best_result = new_result if new_result > best_result
  end
}
sleep 5
thread.exit
puts best_result

Is there a better way to time-box an algorithm in Ruby?

Update

Performance is a key factor.

1 Answers1

1

Use Timeout.

best_result = 0
begin
  timeout(5) do
    while true
      new_result = rand
      best_result = new_result if new_result > best_result
    end
  end
rescue Timeout::Error
  puts "That's enough. Result is #{best_result}"
end

This effectively does the same thing you are doing (execute in another thread, thread gets dead after 5 seconds), but abstracts the timeout handling from your code. And it's in standard library.

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • The exception is a bit odd, since it's not really an exception case (it will always timeout). Nevertheless I think this is a good option. –  Apr 22 '14 at 22:56
  • *This effectively does the same thing* => No, it doesn't. – sawa Apr 22 '14 at 22:59
  • @sawa: Okay, almost the same thing: the roles of the two threads are switched, and the thing being executed in another thread is sleeping. It is functionally equivalent though, unless I'm missing something. – Amadan Apr 22 '14 at 23:03
  • @Amadan The approaches appear functionally equivalent to me. I did a quick and dirty test to compare how far the two approaches get (how many comparisons performed). The timeout approach gets approximately 0.2% further on average. :) –  Apr 22 '14 at 23:13
  • @Amadan You are missing the intent of the code. The code is not checking if something can be done within five seconds and returning an error message if it can't. It is repeating the task as many times as it can for five seconds, and returning the result. It should always run for five seconds. Running for five seconds does not mean that there was not enough time. Well, judging from the comment, even the OP does not seem to know what they are doing. – sawa Apr 22 '14 at 23:37
  • @sawa: Changed the printed text to suit you. But again, it does not matter - the pattern is the same. With access to threads, this is better than evaluating `Time.now` and `Time#-` millions of times - it is clearer, and on my machine it runs 12x the number of iterations compared to yours in the same 5 second interval. "This answer was deleted because the OP hated it"? Please grow up. – Amadan Apr 23 '14 at 00:32
  • @Amadan *Changed the printed text to suit you*-- Don't mistake. It is not to suit me, I don't care. It is to suit the OP's question (if not the OP). Regarding efficiency, I have not said that mine is more efficient than yours (although mine returned the correct result while yours didn't). – sawa Apr 23 '14 at 04:20
  • @Amadan Correct but slow and/or ugly answer should be evaluated more than beautiful/fast but wrong answer. That is all I wanted the OP to realize. – sawa Apr 23 '14 at 04:29
  • This solution also handles the case where the algorithm determines it found the perfect solution and can exit early. –  Apr 23 '14 at 15:16