2013-11-18 2 views
9

У меня есть набор данных, которые я бы хотел сделать в моем приложении rails, каждый расчет не зависит друг от друга, поэтому я хотел бы направить их так, чтобы мои ответ намного быстрее.Выполнение потоков внутри моего контроллера контроллера rails

Вот что у меня есть банкомат:

def show 

    @stats = Stats.new 

    Thread.new { 
    @stats.top_brands = #RESULT OF FIRST CALCULATION  
    } 

    Thread.new { 
    @stats.top_retailers = #RESULT OF SECOND CALCULATION 
    } 

    Thread.new { 
    @stats.top_styles = #RESULT OF THIRD CALCULATION 
    } 

    Thread.new { 
    @stats.top_colors = #RESULT OF FOURTH CALCULATION 
    } 

    render json: @stats 
end 

Теперь это возвращает кучу пустых массивов для каждого из экземпляров членов @stats, однако, если я присоединюсь нить вместе, он работает, но поражения цель резьбы, поскольку каждый из блоков нитей.

Поскольку я очень новичок в потоках, мне интересно, что я делаю неправильно здесь, или если даже можно выполнить то, что я пытаюсь сделать, то есть запустить 4 calcs в paralell и вернуть результат для клиента.

Спасибо,

Джо

ответ

12

Это первая зависит, если ваши расчеты делают тяжелые операции процессора или делают много блокировок ввода-вывода, как чтение из базы данных, файловой системы или сети. Было бы неплохо, если бы они делали первый, поскольку каждый поток занимает процессорное время, и ни один другой поток не может быть запланирован - хуже, даже если вы используете Ruby MRI, который имеет Global Interpreter Lock. Однако, если потоки блокируют IO, они могут, по крайней мере, подождать, позволить другому потоку запустить, подождать, позволить другому запуску и так далее, пока все они не вернутся.

В конце вам нужно объединить все потоки вместе, потому что вам нужны их возвращаемые значения. Сделайте это ниже всех ваших вызовов Thread.new. Сохранить возвращаемое значение каждого Thread.new в массив:

threads = [] 
threads << Thread.new ... 

Затем соединить их вместе, прежде чем вынести:

threads.each &:join 

Если вы действительно хотите быть уверены, что это поможет вам просто эталонное тестирование всего действие:

def show 
    start_time = Time.now.to_f 
    @stats = Stats.new 

    Thread.new { 
    @stats.top_brands = #RESULT OF FIRST CALCULATION  
    } 
    Thread.new { 
    @stats.top_colors = #RESULT OF FOURTH CALCULATION 
    } 

    @elapsed_time = Time.now.to_f - start_time 
    # do something with @elapsed_time, like putsing it or rendering it in your response 

    render json: @stats 
end 

Надеюсь, что это поможет.

+0

Правильно, но для того, чтобы это действительно работало, я должен использовать что-то вроде JRuby правильно? – TheDelChop

+0

Вы по-прежнему увидите ускорение, если вычисления внутри ваших потоков блокируют IO. Это заставляет их спать, а другие потоки могут быть запланированы для начала их работы. Вы можете увидеть, как это работает следующим образом: https://gist.github.com/DiegoSalazar/7547566#file-sleepy_threads-rb Самый быстрый способ, которым вы можете быть уверенным, - сравнить ваши действия с потоками и без них. – DiegoSalazar

+0

Однако было бы лучше в JRuby, Rubinius, Ruby EE, так как они смогут использовать все ядра на вашем компьютере для запуска собственных потоков. – DiegoSalazar

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