Ruby并发I/O.

Trt*_*Trt 5 ruby io multithreading

在此之后, Ruby线程限制 - 也适用于任何语言

我试图理解为什么我的线程不起作用.一些答案非常明确,如:

"使用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"
Run Code Online (Sandbox Code Playgroud)

而我得到的是这......

对于第一个非线程案例:

时间过去15561.358毫秒

对于第二个线程案例:

经过的时间为15442.401毫秒

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

Ste*_*fan 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
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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


如果您更改do_stuff为:

def do_stuff
  sleep(1)
end
Run Code Online (Sandbox Code Playgroud)

结果不同:

                 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)
Run Code Online (Sandbox Code Playgroud)

  • 你不需要等待所有子进程完成吗?您在循环中调用多个forK叉,因此Process.waitall可能是一个更好的举措. (2认同)