EventMachine читает и записывает файлы кусками - PullRequest
2 голосов
/ 21 января 2012

Я использую EventMachine и EM-Synchrony на сервере REST API. Когда я получаю запрос POST с большим двоичным файлом в теле, я получаю его кусками, записывая эти куски в Tempfile, не блокируя реактор.

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

Я вызываю эту функцию через некоторое время, передавая ей временный файл и новое имя файла:

def self.save(tmp_file, new_file)
   tmp = File.open(tmp_file, "rb")
   newf = File.open(new_file, "wb")
   md5  = Digest::MD5.new

   each_chunk(tmp, CHUNKSIZE) do |chunk|
     newf << chunk
     md5.update chunk
   end

   md5.hexdigest
end

def self.each_chunk(file, chunk_size=1024)
  yield file.read(chunk_size) until file.eof?
end

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

Кроме того, я попробовал EM # defer, но мне нужна функция для ожидания завершения процесса чтения / записи, прежде чем он вернет md5, как в моем основном файле, после вызова этой функции я делаю обновление базы данных с возвращаемое значение.

Если кто-то может помочь мне в этом, я был бы благодарен.

РЕДАКТИРОВАТЬ 1

Мне нужно, чтобы функция сохранения возвращалась только после завершения чтения / записи файлов, так как в функции вызова я жду окончательного значения md5, что-то вроде этого:

def copy_and_update(...)
  checksum = SomeModule.save(temp_file, new_file)
  do_database_update({:checksum => checksum}) # only with the final md5 value
end

1 Ответ

1 голос
/ 22 января 2012

Вам нужно вставить что-то туда, чтобы разбить:

def self.each_chunk(file, chunk_size=1024)
  chunk_handler = lambda {
    unless (file.eof?)
      yield file.read(chunk_size)


     EM.next_tick(&chunk_handler)
    end
  }

  EM.next_tick(&chunk_handler)
end

Это немного грязно, но такое асинхронное программирование.

...