6

我已经花了几天时间为 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

4 回答 4

3

两个答案:

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

诚然,惰性方法取决于您正在写入的设备,但是尝试同时将多个大型流写入磁盘将成为主要瓶颈,并且无论如何您都将失去拥有基于事件的服务器的优势。您最终会在各处进行磁盘寻道,IO 性能会直线下降,服务器的性能也会下降。一次处理很多事情对 RAM 来说是可以的,但是一旦你开始处理块设备和 IO 调度,无论你在做什么,你都会遇到性能瓶颈。

但是,我想您可能希望在对其他非 IO 繁重请求做出低延迟响应的同时对磁盘进行一些长时间的写入。所以,也许是个好答案:

使用延迟

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 并发。

但是,如果您确实打算将所有内容写入同一个文件,则必须小心延迟,因为同步问题会出现,因为您的线程可能会尝试同时写入同一个文件。

于 2012-11-01T07:31:19.610 回答
1

docs看来,您只需要附加文件(尽管正如您指出的那样,这可能无效,似乎选项是使用 File.write/ie blocking...)和send_data

尽管我认为您不能将阻塞/非阻塞 IO 与 EM 混合使用 :(

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

也许是谷歌组的一个问题......

〜克里斯

于 2011-01-10T11:47:27.527 回答
1

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

EIO 只会轻轻地疏通反应堆,并为您提供一点点缓冲。如果特定的延迟是一个问题,或者您的磁盘非常慢,那可能会有所帮助。在大多数其他情况下,这可能只是一堆没有优势的努力。

于 2012-04-25T06:03:39.560 回答
0

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

于 2011-01-11T07:28:11.613 回答