Threads in Ruby

To make our applications do multiple things faster at the same time, we can use Ruby threads. For a long-running application, re-using a pool of such threads can provide great performance benefits. Thread pool is a way to have a fixed set of threads doing the work, instead of creating new ones each time.

Considering a simple program as below, we realize the importance of threads.

You will get the sum of each array as output but the sleep(4) instruction will pause execution for 4 seconds and then continue. Thus, group1 will get the sum after 4 seconds, group2 after 8 seconds and so on, which is not feasible. In such cases, it is more economical to have threads, since we can have the sum of each array calculated independently.

Threads allow us to execute different parts of our program independently. For implementing threads, after initializing each array,

The add_element method definition is same but we wrapped method call in a Thread.new block.

Now, instead of getting the sum of each array after 4 seconds, 8 seconds and 12 seconds respectively, you will get the sum of all arrays after 4 seconds. This indicates better performance and efficiency which is the power of threads.

Queue for managing threads

To safely exchange information between threads, we can use Queue in the standard library. The tasks that are added first in the queue are retrieved first. PUSH and POP are the two main methods in Queue that add and retrieves an item respectively.

Consider the following example.

To create new queue instance, use the new() method.

5 items are inserted into the queue.

Output as follows,

Now, to pop off items from queue,

It produces the following output

Sized queue for fixed-length queue

The sized queue is useful in situations where the rate of production is higher than consumption.

In the following example,

We see, 10 items are produced and 4 items are consumed and remaining accumulate in the queue.

This is an issue of memory wastage.

Hence we rely on the sized queue.

Instead of Queue.new, we use SizedQueue.new(maxvalue).

The argument specifies the maximum number of items we allow to put in a queue.

Modifying our example, we can save memory space.

4 threads are produced and consumed. After that, the maximum limit is checked and push operation is blocked. The maximum value of our sized queue is 4 here, so after that push, the operation is not allowed, even though the loop is for 10 times.

Output:

 

To conclude, we can say that while Queue can be used to safely exchange information between threads, SizedQueue helps to overcome the problem with the queue as mentioned above.

References