Почему это работает так, как будто оно не с резьбой?

Я пишу скрипт, который будет пинговать мой диапазон IP-адресов. Вот что у меня так далеко:

lines = `ipconfig`.split("\n")
thr = []
ip_line = lines.detect { |l| l=~/Ip Address/i }
matcher = /\d+\.\d+\.\d+\.\d+/.match(ip_line)
if matcher.length > 0
    address = matcher[0]
    address.sub!(/\.\d+$/,"")
    (1 .. 254).each do |i|
        xaddr = address + "." + i.to_s
        puts "pinging #{xaddr}"
        thr << Thread.new {
            `ping #{xaddr}` 
        }
    end

    thr.each do |t|
        t.join
        output = t.value
        puts output
    end
end

Дело в том, что это выполняется крайне медленно. Как будто приложение не содержит потоков. Это почему? Я заметил, что если я сделаю подкласс Thread, все это будет работать намного быстрее. В чем дело? Разве Нить не предназначена для прямого использования?

4 ответа

Решение

Рубиновые потоки контролируются Ruby Interpreter. для операционной системы Ruby Interpreter - это всего лишь один процесс (как и любые другие процессы). Ruby Interpreter разделил этот процесс на несколько потоков ruby.

`ping #{xaddr}`  

эта строка заставляет Ruby Interpreter временно отказаться от своего контроля, поскольку вы просите операционную систему выполнить другой процесс. Рубиновый интерпретатор не восстановит свой контроль до тех пор, пока не закончится пинг. Вероятно, поэтому код работает медленно.

Вы можете использовать IO.popen, как это

thr << Thread.new xaddr do |adr|
  IO.popen "ping #{adr}" do |io|
    io.each {|l| puts l}
  end
end

Таким образом, вы получите больше параллелизма даже с зелеными нитями. Причина в том, что интерпретатору не нужно ждать, пока будет отправлен полный вывод команды ping.

На какой реализации Ruby вы работаете? В стандартном Ruby потоки являются "зелеными потоками", то есть не реальными потоками операционной системы, а предоставляются средой выполнения Ruby.

В JRuby потоки - это реальные потоки ОС, потому что именно так их реализует JVM.

Таким образом, вы можете увидеть разницу в производительности потоков в разных реализациях Ruby. Обратите внимание, что JRuby считается более быстрым, чем Ruby 1.8.6, хотя Ruby 1.9 быстрее, чем JRuby (по крайней мере, в некоторых тестах).

Хм, похоже, я получаю ту же производительность для

`...`

а также

IO.popen ...

то же самое: http://gist.github.com/511599

Я схожу с ума?

Другие вопросы по тегам