Recipe 3.14. Adding a Timeout to a Long-Running OperationProblemYou're running some code that might take a long time to complete, or might never complete at all. You want to interrupt the code if it takes too long. Solution
Use the built-in
timeout
library. The
Timeout.timeout
method takes a code block and a deadline (in seconds). If the code block finishes running in time, it returns true. If the deadline
The following code would never finish running were it not for the timeout call. But after five seconds, timeout raises a Timeout::Error and execution halts:
# This code will sleep forever… OR WILL IT?
require 'timeout'
before = Time.now
begin
status = Timeout.timeout(5) { sleep }
rescue Timeout::Error
puts "I only slept for #{Time.now-before} seconds."
end
# I only slept for 5.035492 seconds.
Discussion
Sometimes you must make a network connection or take some other action that might be incredibly slow, or that might never complete at all. With a timeout, you can impose an upper limit on how long that operation can take. If it fails, you can try it again later, or
By default,
Timeout.timeout
raises a
Timeout::Error
. You can pass in a custom exception class as the second argument to
Timeout.timeout
: this saves you from having to rescue the
Timeout:Error
just so you can raise some other error that your application
If the code block had side effects, they will still be visible after the timeout
def count_for_five_seconds
$counter = 0
begin
Timeout::timeout(5) { loop { $counter += 1 } }
rescue Timeout::Error
puts "I can count to #{$counter} in 5 seconds."
end
end
count_for_five_seconds
# I can count to 2532825 in 5 seconds.
$counter # => 2532825
This may mean that your dataset is now in an inconsistent state. See Also
|
Chapter 4. ArraysLike all high-level languages, Ruby has built-in support for arrays , objects that contain ordered lists of other objects. You can use arrays (often in conjunction with hashes) to build and use complex data structures without having to define any custom classes. An array in Ruby is an ordered list of elements . Each element is a reference to some object, the way a Ruby variable is a reference to some object. For convenience, throughout this book we usually talk about arrays as though the array elements were the actual objects, not references to the objects. Since Ruby (unlike languages like C) gives no way of manipulating object references directly, the distinction rarely matters.
The simplest way to create a new array is to put a comma-separated list of object references between square brackets. The object references can be predefined
a1 = [] # => [] a2 = [1, 2, 3] # => [1, 2, 3] a3 = [1, 2, 3, 'a', 'b', 'c', nil] # => [1, 2, 3, "a", "b", "c", nil] n1 = 4 n2 = 6 sum_and_difference = [n1, n2, n1+n2, n1-n2] # => [4, 6, 10, -2] If your array contains only strings, you may find it simpler to build your array by enclosing the strings in the w{} syntax, separated by whitespace. This saves you from having to write all those quotes and comma:
%w{1 2 3} # => ["1", "2", "3"]
%w{The rat sat
on the mat}
# => ["The", "rat", "sat", "on", "the", "mat"]
The << operator is the simplest way to add a value to an array. Ruby dynamically resizes arrays as elements are added and removed. a = [1, 2, 3] # => [1, 2, 3] a << 4.0 # => [1, 2, 3, 4.0] a << 'five' # => [1, 2, 3, 4.0, "five"]
An array element can be any object reference, including a reference to another array. An array can even contain a reference to itself, though this is usually a bad idea, since it can send your code into infinite
a = [1,2,3] # => [1, 2, 3] a << [4, 5, 6] # => [1, 2, 3, [4, 5, 6]] a << a # => [1, 2, 3, [4, 5, 6], […]]
As in most other programming languages, the elements of an array are numbered with
indexes
starting from zero. An array element can be
Negative indexes count from the end of the array: the last element of an array can be accessed with a[-1] , the second-to-last with a[-2] , and so on. See Recipe 4.13 for more ways of using the array indexing operator.
The
a = [1, 2, 3, [4, 5, 6]] a.size # => 4 a << a # => [1, 2, 3, [4, 5, 6], […]] a.size # => 5 a[0] # => 1 a[3] # => [4, 5, 6] a[3][0] # => 4 a[3].size # => 3 a[-2] # => [4, 5, 6] a[-1] # => [1, 2, 3, [4, 5, 6], […]] a[a.size-1] # => [1, 2, 3, [4, 5, 6], […]] a[-1][-1] # => [1, 2, 3, [4, 5, 6], […]] a[-1][-1][-1] # => [1, 2, 3, [4, 5, 6], […]]
All languages with arrays have constructs for iterating over them (even if it's just a
for
loop). Languages like Java and Python have general iterator
Ruby's array iterators deserve special study because they're Ruby's simplest and most accessible iterator methods. If you come to Ruby from another language, you'll probably start off thinking of iterator methods as letting you treat aspects of a data structure "like an array." Recipe 4.1 covers the basic array iterator methods, including ones in the Enumerable module that you'll encounter over and over again in different contexts. The Set class, included in Ruby's standard library, is a useful alternative to the Array class for many basic algorithms. A Ruby set models a mathematical set: sets are not ordered, and cannot contain more than one reference to the same object. For more about sets, see Recipes 4.14 and 4.15. |