Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Yes, you can send serialized objects via pipe between different ruby/non-ruby processes!<br/><br/> Let me show you how I do it.<br/><br/> In this example a master process starts a child process, and then child process transmits a simple Hash object using Marshal serialization.<br/></p> <h2>Master source code:</h2> <p>First it would be useful to declare some helper method <strong>run_ruby</strong> in Process class:</p> <pre><code>#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 </code></pre> <p>This code just locates the ruby executable and saves full path into RUBY constant.<br/></p> <blockquote> <p><strong>Important</strong>: If you are going to use <strong>Jruby</strong> or some other executable - you should rewrite this code and provide a path for executing it!</p> </blockquote> <p>Next, we should start child process.<br/> At this moment we can override <strong>STDIN</strong>, <strong>STDOUT</strong> and <strong>STDERR</strong> for new process.<br/> Let us create a <strong>pipe</strong> and redirect child's <strong>STDOUT</strong> to this pipe:</p> <pre><code> rd, wr = IO.pipe Process.run_ruby("./test/pipetest.rb param1 param2", {:out =&gt; wr}) wr.close </code></pre> <p>Please note the options hash: <strong>{:out => wr}</strong> - It tells spawn command to redirect <strong>STDOUT</strong> to <strong>wr</strong> stream descriptor.</p> <p>Also, you can specify params (see <strong>param1</strong> and <strong>param2</strong>) in command line.<br/></p> <p>Note that we call <strong>wr.close</strong> because we do not use it in parent process for this example.<br/></p> <p>How master would receive object:</p> <pre><code>message = rd.gets # read message header with size in bytes cb = message[5..-1].to_i # message is in form: "data &lt;byte_size&gt;\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 </code></pre> <h2>Child source code:</h2> <p>Now, how serialized object will be transmitted?<br/> At first child will serialize object,<br/> then it will send parent message in the form: <code>"data &lt;byte_size&gt;\n"</code><br/> After that it will send serialized object itself.<br/> Child process will send object to <strong>STDOUT</strong> since we have specified to use this channel as a pipe.</p> <pre><code>#encoding: UTF-8 # obj is an example Hash object to be transmitted obj = { 1 =&gt; 'asd', 'data' =&gt; 255, 0 =&gt; 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! </code></pre> <p>In the code above child process simply outputs one serialized object and terminates.<br/> But of course, you can program much more complex behavior.<br/> For instance, I start many child processes, each sharing <strong>one and the same pipe</strong> to parent process at <strong>STDOUT</strong>. To avoid problems with two children writing to pipe simultaneously I have to use <strong>system-level Mutex</strong> (not a Ruby Mutex) to control access to this pipe.<br/></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload