8.1 Computing in Parallel with rinda_eval
In the previous chapter, I mentioned that I didn’t implement eval
because I couldn’t come up with a good way to implement it.
Actually, it’s possible to replicate similar functionality to eval for Portable Operating System Interface for Unix (POSIX)--compliant operating systems.[12] I didn’t include this as part of the standard library, because this doesn’t run on Windows machines and is also very difficult to unit test.
Having said that, you should be able to use rinda_eval
in environments such as Linux or OS X.
We’ll first review what eval
in Linda is like and then move on to the usage of rinda_eval
and its internals.
By the way, don’t be fooled by the word eval. It doesn’t use Ruby’s eval
.
Using eval with Linda
In Linda, there are two operations to generate a tuple: “out” and “eval.” The “out” operation is equivalent to Rinda’s Rinda::TupleSpace#write
.
Here’s an example of generating a tuple that contains the result of a square root from 0 to 9 using the “out” operation:
for (i = 0; i < 10; i++) |
|
out("sqrt", i, sqrt(i)); |
The “eval” operation looks exactly the same as the “out” operation, but there is a big difference. The “eval” operation first generates processes while evaluating arguments and then puts the result into tuples.
Here’s an example of generating ten processes and returning the result in each tuple. It’s important to understand that these newly generated processes evaluate the sqrt
function, not the calling process.
for (i = 0; i < 10; i++) |
|
eval("sqrt", i, sqrt(i)); |
If you think in a normal way, this looks very strange—it should generate processes after each argument is evaluated. Apparently you can do this with C-Linda because it is some sort of preprocessor or language extension, rather than a library.
Rinda::rinda_eval
If you can use a fork
system call in your OS, then you can generate a child process that inherits the entire environment of the Ruby runtime and then continue the process. Rinda::rinda_eval
is implemented using this fork
system call, so it won’t work if your OS doesn’t have fork
. That’s why Rinda::rinda_eval
is targeted for POSIX-compliant systems. This module method creates a new process and then executes the block. You can also pass a reference to TupleSpace
to the arguments so that the returning Array
is added into the tuplespace.
The API isn’t exactly the same as that of C-Linda, but nonetheless this is a practical API. As an example of a practical application, the next example generates worker processes and then stores the results of the calculation into tuples. It consists of two loops. The first loop creates ten worker processes that calculate Math.sqrt
inside a rinda_eval
block, and then the second loop receives the result sets.
10.times do |n| |
|
Rinda::rinda_eval($ts) do |ts| |
|
[:sqrt, n, Math.sqrt(n)] |
|
end |
|
end |
|
10.times do |n| |
|
p $ts.read([:sqrt, n, nil]) |
|
end |
The block passed into rinda_eval
gets executed inside the child processes generated by fork
. The return value of the block will be written to TupleSpace
.