我有一个用Ruby写的map/reduce流pipeline,表现得很奇怪。管道如下所示:
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
答案 0 :(得分:0)
您需要启用sync
。这告诉Ruby 不缓冲输出,而是将其作为输出发送。
将“同步模式”设置为true或false。当sync模式为true时,所有输出立即刷新到底层操作系统,并且不在内部缓冲。
管道应该使用sync
disabled / false,但是在第一个管道,后续管道,看到已关闭的输入,或者它们有完整的缓冲区并冲洗它们之前,您将看不到任何内容,这可能需要一段时间
有关详细信息,请参阅IO.sync=
。