Ruby并发I / O.

时间:2013-06-19 12:23:34

标签: ruby multithreading io

在此之后, Ruby thread limit - Also for any language

我试图理解为什么我的线程无效。 一些答案非常清楚:

“..用fork创建4个子进程将利用你的4个核心” 这将是我最后的方法,因为线程在我的情况下似乎不起作用。

也是这样:

“.. Ruby MRI线程本身不会完全利用运行Ruby代码的多核CPU 。但是,这对你来说是否有问题取决于线程的作用。如果他们在同一台机器上对其他进程进行长时间运行的I / O调用,您将看到好处而无需单独的进程。作为主题的线程和多处理可以变得非常复杂甚至做简单的事情。语言会对容易的和开箱即用的东西做出一些妥协......“

考虑到第二个问题,我已从代码中删除了任何处理,只留下了I / O.

这是:

beginning_time = Time.now
img_processor.load_image(frames_dir+"/frame_0001.png")
img_processor.load_image(frames_dir+"/frame_0002.png")
end_time = Time.now
puts "Time elapsed #{(end_time - beginning_time)*1000} milliseconds"

beginning_time = Time.now
for frame_index in 1..2
    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)
    }
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"

我得到的就是这个...

对于第一个非线程案例:

  

时间已过去15561.358毫秒

对于第二个线程案例:

  

时间已过去15442.401毫秒

好的,性能提升在哪里?我错过了什么吗? 硬盘阻塞了吗? 我是否真的需要生成进程才能在ruby中看到真正的并行性?

1 个答案:

答案 0 :(得分:7)

  

我是否真的需要生成进程才能在ruby中看到真正的并行性?

是的,我想是的:

require 'timeout'
require 'digest'
require 'benchmark'

def do_stuff
  Digest::SHA256.new.digest "a" * 100_000_000
end

N = 10
Benchmark.bm(10) do |x|

  x.report("sequential") do
    N.times do
      do_stuff
    end
  end

  x.report("subprocess") do
    N.times do
      fork { do_stuff }
    end
    Process.waitall
  end

  x.report("thread") do
    threads = []
    N.times do
      threads << Thread.new { do_stuff }
    end
    threads.each(&:join)
  end

end

MRI 2.0.0的结果:

                 user     system      total        real
sequential   3.200000   0.180000   3.380000 (  3.383322)
subprocess   0.000000   0.000000   6.600000 (  1.068517)
thread       3.290000   0.210000   3.500000 (  3.496207)

第一个块(顺序)运行do_stuff 4次,一个接一个,第二个块(子进程)在4个核心上运行,而第三个块(线程)在1个核心上运行。


如果您将do_stuff更改为:

def do_stuff
  sleep(1)
end

结果不同:

                 user     system      total        real
sequential   0.000000   0.000000   0.000000 ( 10.021893)
subprocess   0.000000   0.010000   0.080000 (  1.013693)
thread       0.000000   0.000000   0.000000 (  1.003463)