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
Approach for Installing System Service Implemented as Ruby Gem
How to Break Out of a Map/Collect and Return Whatever Has Been Collected Up to That Point
How to Refresh a Page with Turbolinks
Linux Cli: How to Render Arabic Text into Bitmap
How to Completely Remove Webpack and All Its Dependencies from Rails App
Robustly Call a Flaky API: Proper Error Handling with Net::Http
How to Read from Redis Inside a Multi Block in Ruby
Setting Up .Emacs File for MAC Ruby Development
Ruby (With Rails) Convert a String of Time into Seconds
Initialize Two Variables on Same Line
Get Time from Datetime Variable in Ruby
E: Unable to Locate Package Heroku-Toolbelt
Phonegap and Rails 3: How to Interact with a Rails 3 App
Rails Installation Error :The 'Atomic' Native Gem Requires Installed Build Tools
Ruby Rake Load Tasks from a Gem