Я пишу программу, которая загружает данные из четырех XML-файлов в четыре разные структуры данных. Он имеет такие методы, как это:Производительность Ruby с несколькими потоками по сравнению с одной нитью
def loadFirst(year)
File.open("games_#{year}.xml",'r') do |f|
doc = REXML::Document.new f
...
end
end
def loadSecond(year)
File.open("teams_#{year}.xml",'r') do |f|
doc = REXML::Document.new f
...
end
end
etc...
Первоначально я просто использовал один поток и нагруженные один файл за другим:
def loadData(year)
time = Time.now
loadFirst(year)
loadSecond(year)
loadThird(year)
loadFourth(year)
puts Time.now - time
end
Тогда я понял, что я должен использовать несколько потоков. Мое ожидание, что загрузка из каждого файла на отдельном потоке будет очень близко к четыре раза быстрее, чем делать это все последовательно (у меня есть MacBook Pro с процессором i7):
def loadData(year)
time = Time.now
t1 = Thread.start{loadFirst(year)}
t2 = Thread.start{loadSecond(year)}
t3 = Thread.start{loadThird(year)}
loadFourth(year)
t1.join
t2.join
t3.join
puts Time.now - time
end
То, что я обнаружил, что версия, использующая несколько потоков, на самом деле медленнее, чем другая. Как это возможно? Разница составляет около 20 секунд, каждый из которых занимает от 2 до 3 минут.
Между потоками нет общих ресурсов. Каждый из них открывает другой файл данных и загружает данные в другую структуру данных, чем другие.
Какую версию языка и какую виртуальную машину вы используете? Я считаю, что большинство рубиновых циклов времени все еще используют «зеленые» потоки (читай: на самом деле не многопоточно, а вместо этого эмулируется в одном потоке) –
Я просто использую обычный Ruby версии 1.9.3 (в Windows). Я просто сделал еще несколько исследований и понял, что один из файлов имеет гораздо больше данных, чем другие, поэтому это объясняет, почему производительность не изменилась бы в четыре раза. Но у трех остальных все еще есть минута, поэтому я ожидаю увидеть повышение производительности в течение минуты, используя несколько потоков ... –
У классического рубина есть GIL - вы не получаете вычислительный параллелизм, потому что в целом только один поток выполняется одновременно (с исключениями для IO и некоторых других случаев). попробуйте код с помощью jruby –