Ruby параллелизм / асинхронная обработка (с простым вариантом использования) - PullRequest
6 голосов
/ 25 октября 2010

Я изучал возможности параллельной / асинхронной обработки ruby ​​и прочитал много статей и постов в блоге.Я просмотрел EventMachine, Fibers, Revactor, Reia и т. Д. И т. Д. К сожалению, мне не удалось найти простое, эффективное (и не блокирующее ввод-вывод) решение для этого очень простого варианта использования:

File.open('somelogfile.txt') do |file|
  while line = file.gets      # (R) Read from IO
    line = process_line(line) # (P) Process the line
    write_to_db(line)         # (W) Write the output to some IO (DB or file)
  end
end

Вы видите, мой маленький сценарий выполняет три операции чтение ( R ), процесс ( P ) & записать ( W ).Предположим - для простоты - что каждая операция занимает ровно 1 единицу времени (например, 10 мс), поэтому текущий код будет делать что-то вроде этого (5 строк):

Time:       123456789012345 (15 units in total)
Operations: RPWRPWRPWRPWRPW

Но я бы хотел, чтобысделать что-то вроде этого:

Time:       1234567 (7 units in total)
Operations: RRRRR
             PPPPP
              WWWWW

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

Есть какие-нибудь подсказки о том, как это можно сделать (без переключения с Ruby на Erlang, Closure или Scala)?

Ответы [ 2 ]

3 голосов
/ 25 октября 2010

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

Вы можете использовать что-то вроде DRb для распределения обработки по нескольким процессам / ядрам, но для вашего случая использования это немного много.Вместо этого вы можете попытаться установить связь между несколькими процессами, используя каналы:

$ cat somelogfile.txt | ruby ./proc-process | ruby ./proc-store

В этом сценарии каждый компонент представляет собой собственный процесс, который может работать параллельно, но взаимодействует с использованием STDIN / STDOUT.Это, наверное, самый простой (и самый быстрый) подход к вашей проблеме.

# proc-process
while line = $stdin.gets do
  # do cpu intensive stuff here
  $stdout.puts "data to be stored in DB"
  $stdout.flush # this is important
end

# proc-store
while line = $stdin.gets do
  write_to_db(line)
end
1 голос
/ 25 октября 2010

Check peach (http://peach.rubyforge.org/). Выполнение параллельного «каждого» не может быть проще. Однако, как сказано в документации, вам нужно будет запустить под JRuby, чтобы использовать нативную потоковую реализацию JVM.

См. Ответ Йорга Миттага на этот вопрос SO , чтобы узнать больше о возможностях многопоточности различных интерпретаторов Ruby.

...