我在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之前等待读/写过程完成的功能,就像在我的主文件中一样,在调用这个函数之后我做了一个数据库更新返回值。
如果有人可以帮助我,我将不胜感激。
我需要保存函数只在完成文件读/写后返回,就像在调用函数中我正在等待最终的md5值,如下所示:
def copy_and_update(...)
checksum = SomeModule.save(temp_file, new_file)
do_database_update({:checksum => checksum}) # only with the final md5 value
end
答案 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
这样做很麻烦,但这是异步编程。