【问题标题】:How to write (large) files with Ruby Eventmachine如何使用 Ruby Eventmachine 编写(大)文件
【发布时间】:2012-11-01 15:31:19
【问题描述】:

我现在花了几天时间为 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 块中的磁盘?

感谢您的帮助 安德烈亚斯

【问题讨论】:

    标签: ruby eventmachine


    【解决方案1】:

    两个答案:

    懒惰的回答:只需使用阻塞写入。 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 并发。

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

    【讨论】:

      【解决方案2】:

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

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

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

      也许是google group的问题...

      ~克里斯

      【讨论】:

      • 克里斯,感谢您的回答。 tmm1 的This answer 与文档所说的相冲突(或者我也误解了)。基本上我正在尝试做一个非常简单的文件传输(从套接字读取并将其写入磁盘)......
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-11-04
          • 1970-01-01
          • 1970-01-01
          • 2012-03-18
          • 2011-04-29
          • 2019-06-25
          • 1970-01-01
          相关资源
          最近更新 更多