如何使用Ruby Eventmachine编写(大)文件

时间:2011-01-10 10:28:16

标签: ruby eventmachine

我花了好几天现在为eventmachine找到了一些非echo服务器示例,但似乎没有。假设我想编写一个接受文件并将其写入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 style'。我是否必须以块的形式读取数据并将每个块写入Em.next_tick块中的磁盘?

感谢您的帮助 安德烈亚斯

4 个答案:

答案 0 :(得分:3)

两个答案:

懒惰回答:只使用阻止写入。 EM已经在处理离散的数据块,而不是一个巨大的字符串。所以你的示例实现可能有点偏。您确定要为EM提供的每个块创建一个新的临时文件吗?但是,我将继续假设您的示例代码按预期工作。

不可否认,懒惰方法取决于您正在编写的设备,但尝试同时将几个大型流写入磁盘将成为一个主要瓶颈,您将失去基于事件的优势服务器无论如何。你最终会在整个地方寻找杂乱的磁盘,IO性能将会直线下降,服务器的性能也会下降。使用RAM可以同时处理很多事情,但是一旦你开始处理块设备和IO调度,无论你做什么,你都会遇到性能瓶颈。

但是,我猜你可能想要对磁盘执行一些长写操作,同时希望对其他非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是一个非问题,因为你在这里处理IO阻塞,而不是试图实现CPU并发。

但是如果你打算将所有内容写入同一个文件,那么你必须小心推迟,因为同步问题会出现,因为你的线程可能会同时尝试写入同一个文件。 / p>

答案 1 :(得分:1)

docs开始,您似乎只需要attach该文件(虽然您指出,这可能无效,但似乎可以选择使用File.write / ie blocking ......)和send_data

虽然我认为你不能将阻塞/非阻塞IO与EM混合:(

鉴于源数据是套接字,我想这将由EventMachine处理。

也许是google group ...

的问题

〜克里斯

答案 2 :(得分:1)

不幸的是,文件对选择的接口反应不佳。如果你需要比IO#write更有效的东西(不太可能),那么你可以使用EIO

EIO实际上只会轻轻解锁反应堆,并为您提供少量的缓冲。如果特定延迟是一个问题,或者您的磁盘确实很慢,那可能会有所帮助。在大多数其他情况下,它可能只是一堆努力而没什么好处。

答案 3 :(得分:0)

这与What is the best way to read files in an EventMachine-based app?非常相似(但我想知道如何有效地阅读文件)。似乎没有任何非阻塞文件API,因此您可以做的最好的事情是使用next_tick编写短突发或推迟写入(使用defer)以便它在单独运行线程(但我不知道该解决方案的性能如何)。