如何使用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风格’。 我是否必须以块的forms读取数据并将每个块写入Em.next_tick块中的磁盘?

感谢Andreas的帮助

两个答案:

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

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

从文档中 ,似乎你只需要附加文件(虽然你指出,这可能无效,似乎选项是使用File.write / ie blocking …)和send_data 。

虽然我认为你不能混合阻止/非阻塞IO与EM 🙁

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

也许谷歌小组的一个问题……

〜克里斯

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

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

这非常类似于在基于EventMachine的应用程序中读取文件的最佳方法是什么? (但我想知道如何有效地阅读文件)。 似乎没有任何非阻塞文件API,所以你能做的最好的事情是用next_tick编写短脉冲串或推迟写入(使用defer ),以便它在一个单独的线程中运行(但我不知道关于该解决方案的性能如何)。