2013-07-09 3 views
5

Я пишу программу, которая загружает данные из четырех 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 минут.

Между потоками нет общих ресурсов. Каждый из них открывает другой файл данных и загружает данные в другую структуру данных, чем другие.

+2

Какую версию языка и какую виртуальную машину вы используете? Я считаю, что большинство рубиновых циклов времени все еще используют «зеленые» потоки (читай: на самом деле не многопоточно, а вместо этого эмулируется в одном потоке) –

+0

Я просто использую обычный Ruby версии 1.9.3 (в Windows). Я просто сделал еще несколько исследований и понял, что один из файлов имеет гораздо больше данных, чем другие, поэтому это объясняет, почему производительность не изменилась бы в четыре раза. Но у трех остальных все еще есть минута, поэтому я ожидаю увидеть повышение производительности в течение минуты, используя несколько потоков ... –

+2

У классического рубина есть GIL - вы не получаете вычислительный параллелизм, потому что в целом только один поток выполняется одновременно (с исключениями для IO и некоторых других случаев). попробуйте код с помощью jruby –

ответ

3

Я думаю (но я не уверен) проблема в том, что вы читаете (используя несколько потоков) содержимое, размещенное на одном диске, поэтому все ваши потоки не могут запускаться одновременно, поскольку они ждут ввода-вывода (диска) ,

Несколько дней назад мне приходилось делать аналогичную вещь (но получать данные из сети), а разница между последовательными и потоками была огромной.

Возможным решением может быть загрузка всего содержимого файла, а не загрузка его, как в вашем коде. В вашем коде вы читаете содержимое по строкам. Если вы загружаете все содержимое и затем обрабатываете его, вы должны быть способны выполнять намного лучше (потому что потоки не должны ждать ввода-вывода)

+0

Спасибо, это отличная идея. –

0

Это невозможно дать однозначный ответ на вопрос, почему ваша параллельная проблема медленнее, чем последовательный один без намного больше информации, но одна возможность заключается в том:

С последовательной программы, ваш диск стремится к первому файлу, читает все, ищет второй файл, читает все это и т. д.

С помощью параллельной программы головка диска продолжает перемещаться вперед и назад, пытаясь обслуживать запросы ввода-вывода от всех 4 потоков.

Я не знаю, есть ли способ измерить время поиска диска в вашей системе: если это так, вы можете подтвердить, истинна ли эта гипотеза.

+2

Немного не по теме: Я использовал параллелизм потоков на Ruby для одновременной обработки нескольких сетевых запросов, и это делало чудеса для эффективности моей программы. Это было на MRI (CRuby). Так что вам не обязательно перемещаться в JRuby, чтобы получить какую-либо выгоду от использования потоков для параллельного ввода-вывода. –

Смежные вопросы