Ruby管道流是否异步?

时间:2015-06-03 21:00:07

标签: ruby streaming pipe

我有一个用Ruby写的map/reducepipeline,表现得很奇怪。管道如下所示:

mapper | sort | reducer | expander | sort | splitter | uploader

映射器写入STDOUT(通过puts),reducer从STDIN读取(通过ARGF.each)并写入STDOUT(通过puts)等等。

似乎在上传器执行时,分割器应该创建的文件尚未创建。所以上传者不会上传任何内容。

这是我的Pipeline课程:

class Pipeline

  def run(context)
    raise ArgumentError, 'context is nil' unless context
    raise ArgumentError, 'context[:logger] is nil' unless context[:logger]

    current_path = File.dirname(__FILE__)
    mapper       = File.join(current_path, 'mapper.rb')
    reducer      = File.join(current_path, 'reducer.rb')
    expander     = File.join(current_path, 'expander.rb')
    splitter     = File.join(current_path, 'splitter.rb')
    uploader     = File.join(current_path, 'uploader.rb')

    mapper_args = context[:order_id] == nil ? nil : " #{context[:order_id]}"

    command_line = "ruby #{mapper}#{mapper_args} | sort | ruby #{reducer} | ruby #{expander} | sort | ruby #{splitter} | ruby #{uploader}"

    context[:logger].debug command_line

    %x{#{command_line}}
  end

end

如果管道流在Ruby中是异步的,我想知道做RubyMine会做什么就能解决这个问题。例如,在运行Ruby脚本之前,他们会在命令行之前添加如下代码:ruby -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift)

我已经使用这种技术更新了我的代码,但是,我想知道这是否正确。或者,如果有更好的方法?

class Pipeline

  def run(context)
    raise ArgumentError, 'context is nil' unless context
    raise ArgumentError, 'context[:logger] is nil' unless context[:logger]

    current_path = File.dirname(__FILE__)
    ruby         = 'ruby -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift)'
    mapper       = File.join(current_path, 'mapper.rb')
    reducer      = File.join(current_path, 'reducer.rb')
    expander     = File.join(current_path, 'expander.rb')
    splitter     = File.join(current_path, 'splitter.rb')
    uploader     = File.join(current_path, 'uploader.rb')

    mapper_args = context[:order_id] == nil ? nil : " #{context[:order_id]}"

    create_reports_command_line = "#{ruby} #{mapper}#{mapper_args} | sort | #{ruby} #{reducer} | #{ruby} #{expander} | sort | #{ruby} #{splitter}"

    context[:logger].debug create_reports_command_line

    %x{#{create_reports_command_line}}

    sleep 60 # Sleep for 1 min, just in case...

    upload_reports_command_line = "#{ruby} #{uploader}"

    context[:logger].debug upload_reports_command_line

    %x{#{upload_reports_command_line}}
  end

end

1 个答案:

答案 0 :(得分:0)

您需要启用sync。这告诉Ruby 缓冲输出,而是将其作为输出发送。

  

将“同步模式”设置为true或false。当sync模式为true时,所有输出立即刷新到底层操作系统,并且不在内部缓冲。

管道应该使用sync disabled / false,但是在第一个管道,后续管道,看到已关闭的输入,或者它们有完整的缓冲区并冲洗它们之前,您将看不到任何内容,这可能需要一段时间

有关详细信息,请参阅IO.sync=

相关问题