Ruby线程限制 - 也适用于任何语言

时间:2013-06-19 09:45:52

标签: ruby multithreading

我正在尝试使用Ruby尽可能快地处理1000帧。所以我目前开始1000个线程(每帧一个)。结果很糟糕。它使用大量内存而且速度很慢。我的CPU是http://ark.intel.com/products/67355/ 它说它支持4个线程。 (我猜每个CPU 2个?)。 因此,如果我一次启动4个Ruby线程,等到它们完成,然后再启动4个等等,它将需要250'步骤来完成处理权,而不是1000?

编辑:我的代码现在:

beginning_time = Time.now
    limit=1
for frame_index in 1..limit
    greyscale_frames_threads << Thread.new(frame_index) { |frame_number| 
        puts "Loading Image #{frame_number}"
        img_processor.load_image(frames_dir+"/frame_%04d.png"%+frame_number)
        img_processor.greyscale_image
        img_processor.save_image_in_dir(output_dir,"frame_%04d"%+frame_number)
        puts "Greyscaled Image #{frame_number}"
    }
end

puts "Joining Threads"
greyscale_frames_threads.each { |thread| thread.join } #this blocks the main thread
end_time = Time.now
puts "Time elapsed #{(end_time - beginning_time)*1000} milliseconds"

现在,对于limit = 1,这就是我得到的:

  

经过的时间23504.805999999997毫秒

现在,对于limit = 2,这就是我得到的:

  

经过的时间53465.676毫秒

对于limit = 2,我期待23504.805999999997毫秒。

这意味着我的代码失败了。线程在这里没有任何意义。为什么?有人可以向我解释一下吗?

2 个答案:

答案 0 :(得分:5)

例如,您可以使用此类创建线程池并安排工作:

class Pool
  def initialize(size)
    @size = size
    @jobs = Queue.new
    @pool = Array.new(@size) do |i|
      Thread.new do
        Thread.current[:id] = i
        catch(:exit) do
          loop do
            job, args = @jobs.pop
            job.call(*args)
          end
        end
      end
    end
  end

  def schedule(*args, &block)
    @jobs << [block, args]
  end

  def shutdown
    @size.times do
      schedule { throw :exit }
    end
    @pool.map(&:join)
  end
end

然后,您可以执行pool = Pool.new(32)并在此之后执行以下内容:

pool.schedule do 
  # do your stuff
end

这意味着(在这个例子中)最多会有32个线程,每个线程会弹出你安排的一些工作。

答案 1 :(得分:3)

在标准的ruby解释器中,一次只运行一个线程,因此如果你是计算绑定,则添加线程无济于事。如果您搜索GIL或GVL(全局解释器锁定),您将找到关于此主题的大量内容。如果你是IO绑定的,那么等待IO的线程将放弃控制,因此在这种情况下线程仍然有用。

C扩展也可以放弃GVL,因此可以并行运行多个线程,但这只能在ruby 1.9.3+上进行,并且C扩展需要考虑到这一点。

如果计算并行性对您很重要,您可能需要查看jruby或rubinius,它们都没有GVL。在这两者中,jruby更成熟。

最后,每个任务创建一个线程是浪费的 - 涉及一定数量的开销,因此正常模式是拥有一个可重用的工作线程池。