Чтение файла в EventMachine асинхронно

Я уже некоторое время играю с Ruby EventMachines и думаю, что понимаю его основы.

Однако я не уверен, как эффективно читать большой файл (120 МБ). Моя цель - прочитать файл построчно и записать каждую строку в базу данных Cassandra (то же самое должно быть с MySQL, PostgreSQL, MongoDB и т. д., потому что клиент Cassandra явно поддерживает EM). Простой фрагмент блокирует реактор, верно?

require 'rubygems'
require 'cassandra'
require 'thrift_client/event_machine'

EM.run do
  Fiber.new do
    rm = Cassandra.new('RankMetrics', "127.0.0.1:9160", :transport => Thrift::EventMachineTransport, :transport_wrapper => nil)
    rm.clear_keyspace!
    begin
      file = File.new("us_100000.txt", "r")
    while (line = file.gets)
      rm.insert(:Domains, "#{line.downcase}", {'domain' => "#{line}"})
    end
      file.close
    rescue => err
      puts "Exception: #{err}"
      err
    end
    EM.stop
  end.resume
end

Но как правильно заставить файл читаться асинхронно?


person ctp    schedule 14.10.2011    source источник
comment
возможный дубликат Что такое лучший способ чтения файлов в приложении на основе EventMachine?   -  person Theo    schedule 14.10.2011


Ответы (2)


В EventMachine нет поддержки асинхронного файлового ввода-вывода, лучший способ добиться того, что вы пытаетесь сделать, - прочитать пару строк на каждом тике и отправить их в базу данных. Самое главное — не читать слишком большие куски, так как это заблокирует реактор.

EM.run do
  io = File.open('path/to/file')
  read_chunk = proc do
    lines_sent = 10
    10.times do
      if line = io.gets
        send_to_db(line) do
          # when the DB call is done
          lines_sent -= 1
          EM.next_tick(read_chunk) if lines_sent == 0
        end
      else
        EM.stop
      end
    end
  end
  EM.next_tick(read_chunk)
end

См. Как лучше всего читать файлы в приложении на основе EventMachine?

person Theo    schedule 14.10.2011
comment
Большое спасибо за быстрый ответ ;-) Раньше не знал, что асинхронный ввод-вывод файловой системы невозможен, так что спасибо за подсказку. С другой стороны, я попробовал ваш фрагмент: pastie.org/2696497. Но в этом случае я получил новую ошибку: pastie.org/2696500. Клиент Cassandra поддерживает EM. - person ctp; 14.10.2011
comment
Я понятия не имею, что вызывает эту ошибку, но я изменил две детали в своем примере: ему нужно дождаться возврата вызова БД (фактически yield) перед чтением следующего фрагмента, а также дождаться всех десяти строк... - person Theo; 14.10.2011
comment
Хм, еще какие-то проблемы с асинхронным чтением файлов. Кажется, вызов send_to_db блокирует реактор. Может быть, это то же самое, что вы имеете в виду под ожиданием возврата вызова БД? У вас есть фрагмент кода, что именно вы изменили? - person ctp; 21.10.2011
comment
Вы должны заменить send_to_db вызовом вашего драйвера БД. Если ваш драйвер БД является асинхронным, у него должен быть какой-то способ указать обратный вызов, в этом обратном вызове сделайте то, что находится в блоке. - person Theo; 21.10.2011

Если вы еще этого не сделали, вы можете взглянуть на EM: :FileStreamer. Во-первых, FileStreamer использует «быстрое чтение файлов» на основе C++. Не могли бы вы передать файл через локальный сокет/канал и обработать отправку в базу данных в отдельном процессе, который прослушивает другой конец?

Кроме того, в ThreadedResource, на случай, если это будет полезно... конкретно упоминает Cassandra. Хотя похоже, что ваша библиотека Cassandra основана на Fiber.

person Eric G    schedule 14.10.2011