Derek
Derek

Reputation: 12378

How do you keep a ruby thread alive

Running this

# in initialize
@queue = Queue.new

@threads = Array.new(NUM_THREADS) do
    Thread.new do
      until @queue.empty?
        puts @queue.shift
      end
    end
  end

# later in another method, calling
@threads.each { |t| puts t.alive? } # puts false
@queue.push('something else')
# new item is not processed by thread

How do I keep a Ruby thread alive so it can keep accepting stuff from a queue?

Upvotes: 2

Views: 1059

Answers (2)

Matilda Smeds
Matilda Smeds

Reputation: 1504

You probably want to use Queue from Ruby core library.

Methods pop, deq and shift can be used to retrieve data from the queue. With these methods, according to the documentation

If the queue is empty, the calling thread is suspended until data is pushed onto the queue.

With Queue, your code snippet would look like so

@queue = Queue.new

@threads = Array.new(NUM_THREADS) do
    Thread.new do
      while (item = @queue.shift)
        puts item
      end
    end
  end

# later in another method
@threads.each { |t| puts t.alive? } # true
@queue.push('something else') # is printed out

Queue#shift keeps the thread waiting, until something is pushed into the queue. You still need the loop, so that after handling the item, the thread will stay alive, suspended, waiting for the next item.

Upvotes: 0

max pleaner
max pleaner

Reputation: 26758

The issue is you initialize the threads before adding anything to the queue. The threads start and die before the @queue.push line is run.

If you want to keep alive the thread even if there is nothing in the queue, you can change the logic of the thread so it loops forever:

Thread.new do
  loop do
    if val = @queue.shift
      puts val
    end
  end
end

You could decrease the CPU consumption by putting a sleep call inside the thread's loop, say it sleeps 0.1 seconds each iteration and thus it could process a max of 10 items per second. For example running the following in my Ruby REPL raises the process' CPU consumption from around 0 to 25% (which is undesirably high)

 100.times { Thread.new { loop { } } }

But the following uses less than 1%:

 100.times { Thread.new { loop { sleep 0.1 } } }

There are other ways to manage CPU consumption of background processes other than putting arbitrary sleep numbers in there: for example eventmachine, resque, or sidekiq.

Upvotes: 1

Related Questions