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.
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
A way to share a variable across multiple httpd threads with Rails?
Exactly this is possible using global variables. Global variables in Rails are those that start with a dollar sign, like $count.
Sharing heap between ruby processes
So I figured out this was not possible. Java can do this because of its virtual machine, but unfortunately ruby can't.
How to declare a variable shared between examples in RSpec?
You should use before(:each)
or before(:all)
block:
describe Thing do
before(:each) do
@data = get_data_from_file # [ '42', '36' ]
end
it 'can read data' do
expect(@data.count).to eq 2
end
it 'can process data' do
expect(@data[0].to_i).to eq 42
end
end
The difference is that before(:each)
will be executed for each case separately and before(:all)
once before all examples in this describe/context
. I would recommend you to prefer before(:each)
over before(:all)
, because each example will be isolated in this case which is a good practice.
There are rare cases when you want to use before(:all)
, for example if your get_data_from_file
has a long execution time, in this case you can, of course, sacrifice tests isolation in favor of speed. But I want to aware you, that when using before(:all)
, modification of your @data
variable in one test(it
block) will lead to unexpected consequences for other tests in describe/context
scope because they will share it.
before(:all)
example:
describe MyClass do
before(:all) do
@a = []
end
it { @a << 1; p @a }
it { @a << 2; p @a }
it { @a << 3; p @a }
end
Will output:
[1]
[1, 2]
[1, 2, 3]
UPDATED
To answer you question
describe MyClass do
before(:all) do
@a = []
end
it { @a = [1]; p @a }
it { p @a }
end
Will output
[1]
[]
Because in first it
you are locally assigning instance variable @a, so it isn't same with @a in before(:all)
block and isn't visible to other it
blocks, you can check it, by outputting object_id
s. So only modification will do the trick, assignment will cause new object creation.
So if you are assigning variable multiple times you should probably end up with one it
block and multiple expectation in it. It is acceptable, according to best practices.
ruby / ability to share a single variable between multiple classes
4 years later, ended up relying almost systematically to inheritance for such things, using simple def's, super sometimes, etc... all those are ruby classes native behaviours.
class Base
private
def class_variable
0
end
end
class B < Base
def update
# class_variable is made available by the Base inheritance
class_variable + 1
end
end
class C < B
def update_from_base
# class_variable is made available by A
# B inherit from Base, so we do have class_variable available here
# -> will output 2
class_variable + 2
end
def update
# as we inherit from B, and as B provides and update method
# using super, we're then extending the def update available from B
# -> will output 3
super + 2
end
end
... and so on. It is a simple example; but scales well even for complex business logic, as it tends to help you focus on shared parts of your code base while you organize your classes hierarchically in terms of responsibilities.
Pass variables between separate instances of ruby (without writing to a text file or database)
You need Drb. It works by creating a distributed ruby service(server), a client then connects to it and is able to fetch Ruby objects from it.
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/drb/rdoc/DRb.html
Related Topics
How to Check from Ruby Whether a Process with a Certain Pid Is Running
How to Rescue Model Transaction and Show the User an Error
Profile a Rails Controller Action
Disable Rvm or Use Ruby Which Was Installed Without Rvm
Ruby: How to Make a Public Static Method
Can't Convert Fixnum to String During Rake Db:Create
Possible to Alias a Belongs_To Association in Rails
Sending a Post Request with Net/Http
What Are the Uppercase and Lowercase Rules of Ruby Method Name
Convert String to Decimal Number in Ruby
Token Based Authentication for Rails JSON APIs