Fleet is a simple concurrent programming tool for JTcl. This is a very early release of Fleet and is mostly intended for experimentation. Fleet consists of Java code that implements the "fleet" command and a set of Tcl procedures in the "::fleet" namespace that are used to initialize a fleet and manage message flow to the fleet members. The low level fleet code can be used in many ways. The procs in the ::fleet namespace provide one method to manage concurrent calculations.
::fleet create -name fleet-name
::fleet create creates a new fleet and a new Tcl level command for manipulating fleets.
::fleetName member -name fleet-name
::fleetName member creates a new member of the fleet.
::fleetName tell memberName msg -reply replyCmd -var doneVar
::fleetName tell sends a message representing a script to be executed in the fleet member with name memberName.
The name of the member to send the message to. If memberName is "*" then the same message is sent to all members of the fleet.
A Tcl script that will be executed in by the member in its own interpreter and thread.
A command that will be executed in the Tcl interpreter that sent the message when the command has finished executing.
A variable that will be set in the Tcl interpreter that sent the message when the command has finished executing.
The argument to the procedure specified by a -reply argument, and the variable set with the -var argument, are both Tcl dictionary values with the following key/value pairs:
OK or FAIL depending on the return code of the procedure executed
the name of the fleet that the command was executed in
the name of the fleet member that executed the command
the result of executing the command
the number of items in the members execution key when this result was returned
Example:
set msg {set x [expr {sqrt(3.0)}]} $fl tell $m1 $msg -reply doneCmd
::fleetName forget memberName
::fleetName forget sends a message telling member to forget (remove from its queue) all messages that haven't yet been executed)
::fleetName count -messages memberName
::fleetName count returns a count of items in the fleet. What items are counted depend on the specified arguments.
::fleetName destroy ?memberName?
::fleetName destroy destroys a member (if memberName is specified) or the entire fleet if no memberName argument is present. The destroy message is placed on the members input queue and will not be acted upon until all messages already in the queue are acted upon. Use the forget command to clear the queue if you want the destroy action to happen as soon as the the current message (if any) is done being acted upon.
set fleet [::fleet::initFleet 2 initScript]
This procedure creates a fleet and an associated namespace with parameters set to default values and initializes the fleet members
::fleet::configure $fleet -messageProc sendMessage -calcProc accumulateResults -doneProc reportResults
This procedure creates a fleet and an associated namespace with parameters set to default values and initializes the fleet members
The name of the fleet to configure
The procedure used to send messages to fleet members. Defaults to "messageProc"
The procedure that processes the result value sent back from each member. Defaults to "calcProc"
The procedure called when all messages have been processed. Defaults to "reportProc"
The number of members in fleet (normally set with initFleet command)
If number of items in a fleet members queue falls below this level send more messages. Defaults to 50.
When sending messages send a count that will bring the total in members queue up to the highWater value. Defaults to 100.
The total number of messages that need to be send to complete the calculation currently be performed by fleet. Defaults to 10000.
The number of results that have been returned by the fleet members. Initialized to 0
The number of messages that have been sent to the fleet members. Initialized to 0
eval ::fleet::jproc $fleet $procScript
Send a script representing a Java method to be compiled (using Hyde)
::fleet::reset $fleet
Reset the message counts for the fleet and its members so a new calculation can be begun.
proc readyCmd {args} { puts "done $args" } proc checkReadyVar {varName varElem mode} { upvar #0 $varName var puts $var($varElem) } package require java package require fleet set script { proc count {n} { set x 0.0 for {set i 0} {$i <$n} {incr i} { set x [expr {$x+rand()}] } return $x } } set fl1 [fleet create] set m1 [$fl1 member] set m2 [$fl1 member] $fl1 tell $m1 $script -reply readyCmd $fl1 tell $m2 $script -reply readyCmd for {set i 0} {$i < 10} {incr i} { puts $i $fl1 tell $m1 "count 100000" -reply readyCmd } for {set i 0} {$i < 10} {incr i} { puts $i $fl1 tell $m2 "count 100000" -var readyVar($i) } trace add variable readyVar write checkReadyVar #$fl1 destroy $m1 #$fl1 destroy $m2 vwait done
## Calculate pi using concurrent program ## Compare to example in the Akka "getting started" documentation (http://akka.io) package require hyde package require fleet proc sendMessage {fleet member messageNum} { set nElems 10000 $fleet tell $member "calcPiFor $messageNum $nElems" -reply ::fleet::processReply } proc accumulateResults {value} { global acc set acc [expr {$value+$acc}] } proc reportResults {} { global acc done puts "pi is $acc" set done $acc } set procScript { double calcPiFor {int start int nElem} { double acc = 0.0; int iStart = start*nElem; int iEnd = (start+1)*nElem-1; for (int i=iStart;i<=iEnd;i++) { acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1); } return acc; } } set initScript "package require java" set fleet [::fleet::initFleet 2 $initScript] eval ::fleet::jproc $fleet $procScript ::fleet::configure $fleet -messageProc sendMessage -calcProc accumulateResults -doneProc reportResults ::fleet::configure $fleet -nMessages 10000 -highWater 500 set acc 0.0 ::fleet::sendMessages $fleet vwait done