Search code examples
rubymultithreadingconcurrencyparallel-processingcelluloid

Can't run multithreading with Celluloid


This simple example I run on jruby, but it only one thread runs

require 'benchmark'
require 'celluloid/current'

TIMES = 10

def delay
  sleep 1
  # 40_000_000.times.each{|i| i*i}
end

p 'celluloid: true multithreading?'

class FileWorker
  include Celluloid

  def create_file(id)
    delay
    p "Done!"
    File.open("out_#{id}.txt", 'w') {|f| f.write(Time.now) }
  end
end

workers_pool = FileWorker.pool(size: 10)

TIMES.times do |i|
  # workers_pool.async.create_file(i) # also not happens
  future = Celluloid::Future.new { FileWorker.new.create_file(i) }
  p future.value
end

All created files have interval 1 second.

Please help to turn Celluloid into multithreading mode, where all files are created simultaneously.

Thanks!

FIXED:

Indeed, array of "futures" helps!

futures = []
TIMES.times do |i|
   futures << Celluloid::Future.new { FileWorker.new.create_file(i) }
end
futures.each {|f| p f.value }

Thanks jrochkind !


Solution

  • Ah, I think I see.

    Inside your loop, you are waiting for each future to complete, at the end of the loop -- which means you are waiting for one future to complete, before creating the next one.

    TIMES.times do |i|
      # workers_pool.async.create_file(i) # also not happens
      future = Celluloid::Future.new { FileWorker.new.create_file(i) }
      p future.value
    end
    

    Try changing it to this:

    futures = []
    TIMES.times do |i|
       futures << Celluloid::Future.new { FileWorker.new.create_file(i) }
    end
    futures.each {|f| p f.value }
    

    In your version, consider the first iteration the loop -- you create a future, then call future.value which waits for the future to complete. The future.value statement won't return until the future completes, and the loop iteration won't finish and loop again to create another future until the statement returns. So you've effectively made it synchronous, by waiting on each future with value before creating the next.

    Make sense?

    Also, for short code blocks like this, it's way easier on potential SO answerers if you put the code directly in the question, properly indented to format as code, instead of linking out.

    In general, if you are using a fairly widely used library like Celluloid, and finding it doesn't seem to do the main thing it's supposed to do -- the first guess should probably be a bug in your code, not that the library fundamentally doesn't work at all (someone else would have noticed before now!). A question title reflecting that, even just "Why doesn't my Celluloid code appear to work multi-threaded" might have gotten more favorable attention than a title suggesting Celluloid fundamentally does not work -- without any code in the question itself demonstrating!