ComputeServer is an
AssociativeMemory idiom (or pattern composite) that allows multiple distributed
Masters to submit task and gather results computed by multiple, distributed, and possibly parallel
workers. A Master submit tasks to the
AssociativeMemory. Workers blindly grab Task objects from the
AssociativeMemory, send them the #run method and store its answer back into the
AssociativeMemory. The Master can then retrieve this result. The Task object is usually some implementation of the
CommandPattern. This is a simplification of the
BlackboardMetaphor.
Sample:
This is an example of a simple
ComputeServer using
JavaSpaces. First, we will define the basic
TaskEntry.
JavaSpaces requires the use of concrete classes that implement the
net.jini.core.entry.Entry interface. Since we want to
use it as an abstract class, we will define its
run method to throw a
subclass responsibility exception:
import net.jini.core.entry.Entry;
public
class TaskEntry
implements Entry
{
public ResultEntry run()
{
throw new RuntimeException( "Subclass Responsibility" );
}
}
The
ResultEntry is even simpler:
import net.jini.core.entry.Entry;
public
class ResultEntry
implements Entry
{
}
The worker is pretty straightforward -- it looks for
TaskEntry objects , removes them from
AssociativeMemory, sends them the #run message, and write the
ResultEntry back to
AssociativeMemory. Here's some basic code:
import net.jini.core.entry.Entry;
import net.jini.core.lease.Lease;
import net.jini.space.JavaSpace;
public
class Worker
implements Runnable
{
public void run()
{
JavaSpace space = SpaceAccessor.getDefault();
TaskEntry pattern = new TaskEntry();
for (;;)
{
try
{
TaskEntry aTask = (TaskEntry)
space.take( pattern, null, Long.MAX_VALUE );
Entry result = aTask.run();
if ( result != null )
space.write( result, null, Long.MAX_VALUE );
}
catch ( Exception e )
{
log( e );
}
}
}
}
This can be started from a thread, an exec-process, or from a main. An actual implementation would include leased entries and transactions. We can also create an abstract Master that generates tasks and collects results on discrete threads:
public abstract class Master
{
private JavaSpace m_space;
private Thread m_generator;
private Thread m_collector;
public Master( JavaSpace space )
{
m_space = space;
m_generator = new Thread() {
public void run() {
generate(); } };
m_collector = new Thread() {
public void run() {
collect(); } };
}
public void start()
{
m_generator.start();
m_collector.start();
}
public JavaSpace getSpace()
{
return m_space;
}
abstract public void generate();
abstract public void collect();
}
Now that we have the basic infrastructure in place, we can start using our compute server by defining concrete Task, Result, and Master types.
public class MandelTask extends TaskEntry
{
public Complex x, y;
...
public RsultEntry run()
{
calculate next in mandelbrot in set...
}
}
public
class MandelResult
extends ResultEntry
{
...
public void draw()
{
}
}
The more worker processes we add to the
ComputeServer, the faster the set will be calculated. Of course, this is just an example and the distributed overhead may outweigh the benifits of the compute server. The master for this would look something like the following:
public
class MandelMaster
extends Master
{
public MandelMaster()
{
super( Space.getDefault() );
}
public void generate()
{
while ( complex points )
{
getSpace().write( new MandelTask( params 0 ) );
}
}
public void collect()
{
Entry pattern = new MandelResult();
while ( more to collect )
{
MandelResult result = (MandelResult)
getSpace().take( pattern, null, Long.MAX_VALUE );
result.draw();
}
}
}
When you call master #start, the collector thread will start plotting the results on the screen as soon as they are generated.
A good example of the
ComputeServer pattern is the
SetiAtHome screen saver project (
http://setiathome.ssl.berkeley.edu/sciencepaper.html).
SetiAtHome uses multiple, autonomously collaborating unskilled workers (your computer in screen saver mode) that continually grab tasks (figures to be analyzed), process them, and return the results to an
AssociativeMemory (i.e. SETI).
Processes posting tasks, processes retrieving results, and processes that are removing and executing Tasks from
AssociativeMemory operate collaboratively but autonomously -- they aren't aware of each other. One can bring on new workers without disturbing the system. Adding a new processor will usually result in increased performance. You also see this style used a lot in crypto-analysis. Unlike the
BlackboardMetaphor, the algorithm is specialized within the actual Task Tuple. --
RobertDiFalco (this comment was edited and moved from
TupleSpace)
See also: GenerativeCommunication