EventMachine以块的形式读写文件

时间:2012-01-21 19:38:10

标签: ruby eventmachine

我在REST API服务器中使用EventMachine和EM-Synchrony。当接收到一个带有大型二进制文件的POST请求时,我会以块的形式接收它,将该块写入Tempfile,而不是阻塞反应堆。

然后,在某些时候,我需要以块的形式读取此文件并将该块写入确定的文件。这是有效的,但它会按预期阻塞反应堆,并且无法找到一种方法使其无阻塞地工作。

我会在某个时候调用此函数,并将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 个答案:

答案 0 :(得分:1)

你需要在那里注入一些东西来分解它:

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

这样做很麻烦,但这是异步编程。