Как писать (большие) файлы с помощью Ruby Eventmachine - PullRequest
6 голосов
/ 10 января 2011

Я потратил несколько дней, чтобы найти примеры не-эхо-серверов для eventmachine, но, похоже, их просто нет.Допустим, я хочу написать сервер, который принимает файл и записывает его в Tempfile:

require 'rubygems'
require 'tempfile'
require 'eventmachine'

module ExampleServer

  def receive_data(data)
    f = Tempfile.new('random')
    f.write(data)
  ensure
    f.close
  end

end

EventMachine::run {
  EventMachine::start_server "127.0.0.1", 8081, ExampleServer
  puts 'running example server on 8081'
}

Запись в файл блокирует реактор, но я не понимаю, как это сделать 'Стиль Eventmachine».Должен ли я читать данные по частям и записывать каждый кусок на диск в блоке Em.next_tick?

Спасибо за любую помощь, Андреас

Ответы [ 4 ]

3 голосов
/ 01 ноября 2012

Два ответа:

Ленивый ответ: просто используйте блокирующую запись.EM уже передает вам отдельные куски данных, а не одну гигантскую строку.Так что ваш пример реализации может быть немного не так.Вы уверены, что хотите создать новый временный файл для каждого куска, который EM вручает вам?Тем не менее, я продолжу исходить из предположения, что ваш пример кода работает так, как задумано.

По общему признанию, ленивый подход зависит от устройства, на которое вы пишете, но пытаясь одновременно записать несколько больших потоков на диск вТо же самое может стать серьезным узким местом, и вы все равно потеряете свои преимущества, связанные с наличием сервера на основе событий.Вы просто получите жонглирование дисковым поиском повсюду, производительность ввода-вывода упадет, как и производительность вашего сервера.Одновременная работа со многими вещами - это нормально с ОЗУ, но как только вы начнете работать с блочными устройствами и планированием ввода-вывода, вы столкнетесь с узкими местами производительности независимо от того, что вы делаете.Возможно, вы захотите сделать несколько длинных операций записи на диск в то же время, когда вы хотите получить ответы с низкой задержкой на другие запросы, не связанные с IO.Так что, возможно, хороший ответ:

Используйте defer .

require 'rubygems'
require 'tempfile'
require 'eventmachine'

module ExampleServer

  def receive_data(data)
    operation = proc do
      begin
        f = Tempfile.new('random')
        f.write(data)
      ensure
        f.close
      end
    end

    callback = proc do
      puts "I wrote a file!"
    end

    EM.defer(operation, callback)
  end

end

EventMachine::run {
  EventMachine::start_server "127.0.0.1", 8081, ExampleServer
  puts 'running example server on 8081'
}

Да, это действительно использует многопоточность.Это действительно не так уж и плохо в этом случае: вам не нужно беспокоиться о синхронизации между потоками, потому что EM достаточно хорош, чтобы справиться с этим для вас.Если вам нужен ответ, используйте обратный вызов, который будет выполнен в главном потоке реактора после завершения рабочего потока.Кроме того, GIL не является проблемой для этого случая, так как вы имеете дело с блокировкой ввода-вывода и не пытаетесь достичь параллелизма ЦП.

Но если вы намеревались записать все в одно и то жефайл, вам нужно быть осторожным с отсрочкой, так как проблема синхронизации возникнет, поскольку ваши потоки, вероятно, будут пытаться записать в тот же файл в то же время.

1 голос
/ 25 апреля 2012

К сожалению, файлы плохо реагируют на выбранные интерфейсы.Если вам нужно что-то более эффективное, чем запись IO # (что маловероятно), тогда вы можете использовать EIO .

EIO действительно только слегка разблокирует реактор и предоставит вам небольшой кусочекбуферизации.Если определенные задержки являются проблемой, или у вас действительно медленные диски, это может быть полезно.В большинстве других случаев это, вероятно, просто куча усилий для небольшого преимущества.

1 голос
/ 10 января 2011

Из документов кажется, что вам просто нужно прикрепить файл (хотя, как вы отмечаете, это может быть недопустимым, кажется, вариант - использовать File запись / то есть блокировка ...) и send_data .

Хотя я думал, что вы не можете смешивать блокирующий / неблокирующий ввод-вывод с EM: (

Учитывая, что исходные данные являются сокетом, я думаю, что он будет обрабатываться EventMachine.

Возможно, вопрос для группы Google ...

~ * Крис 1017 *

0 голосов
/ 11 января 2011

Это очень похоже на Каков лучший способ чтения файлов в приложении на основе EventMachine? (но я хотел знать, как эффективно читать файлы).Кажется, что не существует никакого неблокирующего API для файлов, поэтому лучшее, что вы можете сделать, это написать короткие пакеты с next_tick или отложить запись (с defer), чтобы он выполнялся в отдельном потоке (но яне знаю, насколько эффективным является это решение).

...