我需要使用Marshal在Ruby中序列化一个对象,并通过管道将其发送给子进程。我该怎么做呢?
我的代码如下所示,我的问题在注释中:
data = Marshal.dump(data)
#call sub-process
`ruby -r a_lib -e 'a_method'` #### how to send the stdout to the subprocess?
a_method看起来像这样:
def a_method
...
data = Marshal.load(data) #### how to load the stdout of the parent process?
...
end
发布于 2012-11-06 19:32:26
是的,你可以通过管道在不同的ruby/非ruby进程之间发送序列化的对象!
让我告诉你我是怎么做的。
在本例中,主进程启动一个子进程,然后子进程使用Marshal序列化传输一个简单的Hash对象。
主源代码:
首先,在Process类中声明一些辅助方法run_ruby会很有用:
#encoding: UTF-8
require 'rbconfig'
module Process
RUBY = RbConfig::CONFIG.values_at('bindir', 'BASERUBY').join('/')
# @param [String] command
# @param [Hash] options
def Process.run_ruby(command, options)
spawn("#{Process::RUBY} -- #{command}", options)
end
end
这段代码只是定位ruby可执行文件,并将完整路径保存到RUBY常量中。
重要的:如果你打算使用,Jruby,或者其他可执行文件,你应该重写这段代码,并提供一个执行它的路径!
接下来,我们应该启动子进程。
此时,我们可以为新流程覆盖STDIN、STDOUT和STDERR。
让我们创建一个管道,并将孩子的STDOUT重定向到这个管道:
rd, wr = IO.pipe
Process.run_ruby("./test/pipetest.rb param1 param2", {:out => wr})
wr.close
请注意选项hash:{:out => wr} - It告诉spawn命令将STDOUT重定向到wr流描述符。
此外,还可以在命令行中指定参数(请参见param1和param2)。
请注意,我们之所以调用wr.close,是因为在本例中,我们没有在父进程中使用它。
master如何接收object:
message = rd.gets # read message header with size in bytes
cb = message[5..-1].to_i # message is in form: "data <byte_size>\n"
data = rd.read(cb) # read message with binary object
puts "Parent read #{data.length} from #{cb} bytes:"
obj = Marshal::load(data) # unserialize object
puts obj.inspect
子源代码:
现在,序列化的对象将如何传输?
第一个子级将序列化对象,
然后,它将以以下形式发送父消息:"data <byte_size>\n"
之后,它将发送序列化的对象本身。
子进程会将对象发送到STDOUT,因为我们已经指定将此通道用作管道。
#encoding: UTF-8
# obj is an example Hash object to be transmitted
obj = {
1 => 'asd',
'data' => 255,
0 => 0.55
}
data = Marshal::dump(obj) # serializing object (obj)
$stdout.puts "data #{data.length}" # sending message header
$stdout.write data # sending message itself
$stdout.flush # Important: flush data!
在上面的代码中,子进程只是输出一个序列化的对象并终止。
当然,您可以编写更复杂的行为。
例如,我启动了许多子进程,每个子进程在STDOUT中共享一个到父进程的管道。为了避免两个孩子同时写入管道时出现的问题,我必须使用系统级互斥锁(而不是Ruby Mutex)来控制对这个管道的访问。
发布于 2012-08-10 11:10:29
您可以使用IO::pipe
方法。
我认为你选择的创建子进程的方法不是最好的。Backticks在后台执行fork
和exec
,ruby
命令也执行fork
和exec
。这意味着您的命令:
`ruby -r a_lib -e 'a_method'`
执行以下操作:派生当前进程,将其转换为shell进程,派生shell进程,将其转换为ruby进程。
我建议使用fork
方法:
data = Marshal.dump(data)
reader, writer = IO.pipe
reader.close # parent process will be on the writing side of the pipe
writer.puts data
#call sub-process
fork do
writer.close # child process can only read from the pipe
data = reader.gets
# whatever needs to be done with data
end
https://stackoverflow.com/questions/11898528
复制