Squeak
  links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
RemoteTask
Last updated at 5:59 am UTC on 14 November 2011
Contributed by Dave Lewis (lewis@mail.msen.com)

A RemoteTask represents a block to be evaluated in a headless Squeak child process. The results of evaluating the block are returned to the sender through a reference stream on an OS pipe. Asynchronous event notification may be used to signal completion of remote processing.

A task block is evaluated in a remote headless image beginning with a clone of the sender image at the time of the message send. All side effects of evaluating the task block are localized to the remote image, and have no effect on the sending image. The result object may be an object of any complexity, such as a dictionary or array of result values. When the task is complete, the parent image is notified of data availability and a completion block is activated to handle the result in the parent image.

On a unix system, the creation of child Squeak images is a relatively light weight operation, so tasks of varying degrees of complexity can be assigned to remote tasks with only moderate overhead.

RemoteTask may be used to assign tasks to worker images in separate OS processes. This is useful for a multiprocessor platform on which processes may be assigned to separate CPU cores, such that large computational tasks may run in parallel with reduced processing time and little effect on the parent image.

RemoteTask may also be used to assign operations that block the VM to separate processes. For example, an FFI call to a long running external library function may be assigned to a remote task, such that the VM for the parent image is not blocked by the FFI call.

RemoteTask is part of the latest CommandShell package on SqueakSource (CommandShell 4.5.0), and requires OSProcess as well as a Unix or Mac VM with OSProcessPlugin (it is helpful if the VM also has AioPlugin for process completion notification, although polling will be used if this is not present). RemoteTask is tested only on Linux with standard VM and Cog, although it will probably work on Mac also (confirmation would be appreciated).

RemoteTask works by using an OSProcess #forkSqueak to create a clone of the running image in a separate OS process. The child image evaluates a task block and writes the results to a ReferenceStream on an OS pipe connected to the parent image. The parent uses AIO event notification to detect when data is available, then reads the result object using a ReferenceStream on its end of the OS pipe and handles the result object in a completion block.

Examples

Evaluate the expression 2 + 2 in a remote image, and inspect the result in the local image:

(RemoteTask do: [2 + 2]) inspect

In a remote image, wait 3 seconds before evaluating the expression 2 + 2, then send the result to the parent image. Set an asynchronous notifier in the parent image that inspects the result of the remote task when complete (inspect the remote task while processing in order to prevent it being garbage collected).

(RemoteTask
do: [(Delay forSeconds: 3) wait. 2 + 2]
whenComplete: [ :result | result inspect ]) inspect

Assign three processing tasks assigned to three Squeak worker images with results returned to the supervisory image on task completion.

threeParallelTasks
"Find all primes in a range of large integers. Divide the problem into
three tasks running the three child images, and return the results to
the supervisory image. Answer a tasks array and a results array, where
the results array will be populated on completion of the tasks."

"RemoteTask threeParallelTasks"

| p1 p2 p3 results task1 task2 task3 |
results := Array new: 3.
task1 := [(100000000000000000000000000000
to: 100000000000000000000000019999)
select: [:f | f isPrime] thenCollect: [:s | s asString]].
task2 := [(100000000000000000000000020000
to: 100000000000000000000000039999)
select: [:f | f isPrime] thenCollect: [:s | s asString]].
task3 := [(100000000000000000000000040000
to: 100000000000000000000000059999)
select: [:f | f isPrime] thenCollect: [:s | s asString]].
"n.b. Assign task to a variable to prevent RemoteTask from being finalized"
p1 := RemoteTask do: task1 whenComplete: [:result | results at: 1 put: result].
p2 := RemoteTask do: task2 whenComplete: [:result | results at: 2 put: result].
p3 := RemoteTask do: task3 whenComplete: [:result | results at: 3 put: result].
^ { #tasks -> { p1 . p2 . p3 } . #results -> results }