Is Communication Between Two Ruby Processes Possible/Easy

Is communication between two ruby processes possible/easy?

Ruby provides many mechanisms for this including your standards such as: sockets, pipes, shared memory. But ruby also has a higher level library specifically for IPC which you can checkout Here, Drb. I haven't had a chance to play around with it too much but it looks really cool.

How to use Unix Socket to communicate between ruby and Python

You were close, but Ruby spawn closes any file descriptors > 2 by default, unless you pass :close_others => false as argument. See the documentation:

http://apidock.com/ruby/Kernel/spawn

Working example:

require 'socket'

r_socket, p_socket = Socket.pair(:UNIX, :DGRAM, 0)

pid = Process.spawn('python', 'p.py', p_socket.fileno.to_s,
{ :close_others => false })

# Close the python end (we're not using it on the Ruby side)
p_socket.close

# Wait for some data
puts r_socket.gets

# Wait for finish
Process.waitpid(pid)

Python:

import sys
import socket

p_fd = int(sys.argv[1])
p_socket = socket.fromfd(p_fd, socket.AF_UNIX, socket.SOCK_DGRAM)

p_socket.send("Hello world\n")

Test:

> ruby p.rb
Hello world

Shared Variable Among Ruby Processes

One problem is you need to use Process.wait to wait for your forked processes to complete. The other is that you can't do interprocess communication through variables. To see this:

@one = nil
@two = nil
@hash = {}
pidA = fork do
sleep 1
@one = 1
@hash[:one] = 1
p [:one, @one, :hash, @hash] #=> [ :one, 1, :hash, { :one => 1 } ]
end
pidB = fork do
sleep 2
@two = 2
@hash[:two] = 2
p [:two, @two, :hash, @hash] #=> [ :two, 2, :hash, { :two => 2 } ]
end
Process.wait(pidB)
Process.wait(pidA)
p [:one, @one, :two, @two, :hash, @hash] #=> [ :one, nil, :two, nil, :hash, {} ]

One way to do interprocess communication is using a pipe (IO::pipe). Open it before you fork, then have each side of the fork close one end of the pipe.

From ri IO::pipe:

    rd, wr = IO.pipe

if fork
wr.close
puts "Parent got: <#{rd.read}>"
rd.close
Process.wait
else
rd.close
puts "Sending message to parent"
wr.write "Hi Dad"
wr.close
end

_produces:_

Sending message to parent
Parent got: <Hi Dad>

If you want to share variables, use threads:

@one = nil
@two = nil
@hash = {}
threadA = Thread.fork do
sleep 1
@one = 1
@hash[:one] = 1
p [:one, @one, :hash, @hash] #=> [ :one, 1, :hash, { :one => 1 } ] # (usually)
end
threadB = Thread.fork do
sleep 2
@two = 2
@hash[:two] = 2
p [:two, @two, :hash, @hash] #=> [ :two, 2, :hash, { :one => 1, :two => 2 } ] # (usually)
end
threadA.join
threadB.join
p [:one, @one, :two, @two, :hash, @hash] #=> [ :one, 1, :two, 2, :hash, { :one => 1, :two => 2 } ]

However, I'm not sure if threading will get you any gain when you're IO bound.

Is mmap the best way to communicate between processes?

one advantage of mmap over physical file is indeed speedup, but anything is going to be faster than a physical file !

the easiest way to communicate between to processes is either a pipe or a socket. they are easier because they are streams, so they do not impose a limit on the length of the data you can exchange between the processes, contrary to a file or a mmap which have bounds.

ruby interprocess communication

I implemented a system via RabbitMq + the bunny gem.

Update:

After reading http://blog.brightbox.co.uk/posts/queues-and-callbacks I decided to try out RabbitMQ. There are two gems amqp (async, eventmachine based) or bunny (sync). amqp is great, but if you're using Rails with passenger it can do some weird things.

The system works like this, the daemons listen on a queue for messages:

# The incoming data should be a JSON encoded hash that looks like:
# { "method" => method_to_call, "opts" => [ Array of opts for method ],
# "output" => "a queue where to send the result (optional)" }
# If output is specified it will publish the JSON encoded response there.
def listen_on(queue_name, class)
BUNNY.start
bunny = BUNNY.queue(queue_name)

bunny.subscribe do |msg|
msg = JSON.parse(msg[:payload])

result = class.new.send(msg["method"], *msg["opts"])

if msg["output"]
BUNNY.queue(msg["output"]).publish(result.to_json)
end
end

So once a message is received it calls a method from a class. One thing to note is that it would have been ideal to use bunny for Rails and amqp in the daemons. But I like to use one gem pe service.

Using file to exchange messages between two processes

You can call a WebService inside Excel see this post

In your C# application you can write a simple basic WCF see this example

TCP Socket communication between processes on Heroku worker dyno

Have you tried Fifo?

http://www.gnu.org/software/libc/manual/html_node/FIFO-Special-Files.html#FIFO-Special-Files

Share variable through ruby processes

When you fork a process then the child and parent processes's memory are separated, so you cannot share variables between them directly. So a singleton class will not work in your case.

The solution is IPC, Ruby supports both pipes and sockets, which are the two most used forms of IPC, at least on *NIX. Ruby also supports distributed objects, if you need a more transparent interface.

What you chose depends on the job. If you know you want to split you processes over several computers at some point, go with sockets or drb. If not go with pipes.

Here's a short introduction to pipes in Ruby



Related Topics



Leave a reply



Submit