One of a series of tutorials about Scheme in general
and the Wraith Scheme interpreter in particular.
Copyright © 2011
Jay Reynolds Freeman,
all rights reserved.
Personal Web Site: http://JayReynoldsFreeman.com
One of Wraith Scheme's major enhancements above and beyond standard R5 Scheme is the capability to do parallel processing. Several tutorials provide guidance on how to use that capability. The main purpose of this tutorial is simply to tell you in a very general way what kind of parallel processing Wraith Scheme can do, and to show you how to configure Wraith Scheme so that it is set up to do it.
If you are running Wraith Scheme the way it came "out of the box", then whenever you start it running, only one Wraith Scheme window opens. This window is the user interface to one instance of a Wraith Scheme process, or I might better use the standard Macintosh terminology and say "one instance of a Wraith Scheme application", instead. That window probably looks a lot like this image
and there will be no other windows anything like it anywhere to be seen.
Wraith Scheme provides the capability to run multiple instances of the Wraith Scheme application at the same time, and these instances can communicate with each other, both by sharing Scheme main memory and by exchanging messages. To make that happen, open the Wraith Scheme Preferences Window
and press the "Kittens" tab at the top of that window, so that the preferences window looks like this.
At this point I should mention -- in case you haven't noticed -- that Wraith Scheme uses a feline metaphor from time to time. Thus when a group of Wraith Scheme applications are cooperating in parallel, I describe them as if they were a family of cats. Each of the cooperating processes has a number that identifies it within the family. This number is called its kitten number.
One of the cooperating processes has special responsibilities and special privileges. Part of its job is to take a central or leading role in certain parallel operations -- we will see what these are later. This special process is called the MomCat, and its kitten number is always zero.
The other Wraith Scheme applications of the cooperating group are called kittens, and the image of a frazzled mother cat trying to ride herd on a bunch of rambunctious kittens is not far from the truth for what actually goes on in many parallel applications. The kitten numbers of the kittens start at 1 and increase.
The panel of the Wraith Scheme Preferences Window that you have just opened is where you tell Wraith Scheme how many kittens you would like to use. That information is used only when Wraith Scheme starts up -- there is no way to add kittens when Wraith Scheme is running. (When there are already some kittens running, you can cause some of them to quit, but that is another matter.) If the number is zero -- which is the way it is set up when you first download Wraith Scheme -- then when you start Wraith Scheme, only one Wraith Scheme application will open. It will in fact be the MomCat of a family with no kittens, and its kitten number will be zero, but the fact that it is the MomCat doesn't matter very much, since there are no kittens who need tending.
So let's make a bigger family. Set the number of kittens in that window to something other than zero. I suggest 3 for a start. That will be four Wraith Scheme applications running altogether -- the MomCat and kittens 1, 2 and 3. Wraith Scheme will not allow any number of kittens greater than 15 at the moment, and if you use too many and actually try to do something with them, they will quite happily use up all the processing power that your Macintosh has, and both Wraith Scheme and any other applications you may have open will be slow and unresponsive. As a rule of thumb, I suggest that the total number of Wraith Scheme processes you are using not exceed twice the number of processor cores on your Macintosh. Wraith Scheme requires a Macintosh with an Intel processor, and all Intel Macs have at least two cores, so three kittens -- four Wraith Scheme processes in all -- should be okay.
Once you have set the number of kittens specified in the Wraith Scheme preferences to 3, quit from Wraith Scheme and start it up again. This time, four Wraith Scheme windows will open. One will look like the single Wraith Scheme window you have gotten used to by now, except that it will say "MomCat" in its title. The other three, for the kittens, will be different colors, and their icons in the dock will be colored to match. The new windows will have their kitten numbers showing in their title bars, and the icons will also display the kitten numbers as little badges about where you would expect a cat's name tag to be.
Here is a screen shot of Wraith Scheme running with a MomCat and three kittens.
Note the pastel red, green and blue cat-face icons near the right end of the dock, at the bottom of the screen. Those are the icons for the three kittens. The icon for the MomCat is to their left, and looks the way it does when you are only using a single Wraith Scheme process. In case you are wondering, yes, all fifteen kittens do have their own unique colors for icons and window backgrounds.
Two items in Wraith Scheme's Window Menu help with arranging the various Wraith Scheme windows.
The "Bring All Kittens to Front" menu item does exactly that. The "Bring Kitten to Front" menu item opens a submenu that allows you to bring a specific kitten to the front of your screen.
The Wraith Scheme Help File has a large section that goes into great detail about Wraith Scheme parallel processing, and discusses many associated procedures. I will mention some of them here. Procedure "e::momcat?" is a predicate that returns whether or not the Wraith Scheme process in which it is evaluated is the MomCat. Procedure "e::kitten-number" returns the kitten number of the Wraith Scheme process in which it is evaluated. Procedure "e::number-of-kittens" returns the number of kittens that were present when the group of parallel Wraith Scheme processes was started, not counting the MomCat. This number does not change if a kitten exits or crashes.
Every group of parallel Wraith Scheme processes must have a functioning MomCat. If the MomCat crashes, or if you inadvertently make that process quit, the remaining Wraith Scheme processes cannot continue to function for very long. For that reason, if you use the "Quit" command in the MomCat, it will cause all kittens to quit as well. On the other hand, you are free to cause any other kitten to quit, if you wish. Doing so should not interfere with the ability of the MomCat and any remaining kittens to cooperate.
The main reason why the MomCat is essential is that one of the MomCat's special duties and responsibilities is coordinating garbage collection. We haven't talked about garbage collection very much yet, though it will be the subject of a subsequent tutorial. Suffice it to say that getting garbage collection to work in the presence of a horde of active kittens requires a strong central authority. If there is no central authority -- no MomCat -- there is no garbage collection, and if Wraith Scheme cannot collect garbage, it will fail as soon as its allotment of memory is full.
To demonstrate that the MomCat and kittens indeed share memory, evaluate any "define" expression you like in any Wraith Scheme window -- MomCat or kitten. Then go to some other window and type and evaluate the name of the variable you just defined. You will see that Wraith Scheme reports the correct value of that variable, no matter where you type it.
To demonstrate that the different Wraith Scheme processes really can run code at the same time, you might try defining a couple of properly tail recursive procedures and starting them running in different Wraith Scheme windows. Try
(define (foo) (display "foo ") (foo)) ;; ==> foo (define (bar) (display "bar ") (bar)) ;; ==> bar (define (baz) (display "baz ") (baz)) ;; ==> baz
If you have any software tools that show how much work the different processor cores of your Macintosh are doing, you might use them to notice that when you start procedures running in many Wraith Scheme windows, the processor cores indeed get busy. (Apple provides several such tools, and other vendors provide them as well.)
Here is an example of how one Wraith Scheme process can ask another to do something. The procedure for this is "e::tell-kitten", and it takes two arguments. The first is a kitten number, and the second is something that you would like that kitten to evaluate. If you evaluate this in the MomCat
(e::tell-kitten 1 '(+ 2 2))
and then look in the window for kitten 1, you will find the number "4" printed out there.
There is a subtle detail about "e::tell-kitten" that may cause you trouble: It is a procedure, and you know by now that the arguments for procedures are evaluated before being passed to the procedures themselves. Hence the quote in "(e::tell-kitten1 '(+ 2 2))" is significant. That expression -- "'(+ 2 2)" -- will be evaluated on the MomCat, to the unquoted list "(+ 2 2)", before being passed to "e::tell-kitten". Procedure "e::tell-kitten" passes its argument to the kitten indicated, to be evaluated there, so that kitten 1 indeed evaluates "(+ 2 2)". But without the quote, the (unquoted) expression "(+ 2 2)" would have been evaluated on the MomCat, not on kitten 1, and only the result -- the number "4" -- would have been passed to kitten 1 to be evaluated there.. If you had been counting on kitten 1 to do some real work on your behalf, perhaps passing it a procedure application much longer and fancier than "(+ 2 2)", then omitting the quote would have forced the procedure to be evaluated on the MomCat, and kitten 1 would have had a chance to be lazy.
To make this point clearer, try evaluating the following two expressions in the MomCat. They differ only by the presence or absence of a quote.
(e::tell-kitten 1 '(e::kitten-number)) ;; ==> A "1" gets printed in kitten 1 (e::tell-kitten 1 (e::kitten-number)) ;; ==> A "0" gets printed in kitten 1
What is happening is that the first evaluation causes the entire expression "(e::kitten-number)" to be passed to kitten 1 and evaluated there: The quote is "removed" when the argument, "'(e::kitten-number)" is evaluated before being passed to "e::kitten-number". Kitten 1's kitten number is indeed "1", so that is what gets printed out. Without the quote, however, "(e::kitten-number)" is evaluated on the MomCat, where the kitten number is 0, and it is that value alone that gets passed to kitten 1 to be evaluated and printed.
Subsequent tutorials will provide some hints and guidance for how to make good use of Wraith Scheme's parallel processing capabilities in your own programs -- and for a few things to avoid. I hope the present tutorial has shown you enough about how to configure Wraith Scheme for parallel processing so that you can try things out for yourself now if you feel so inclined, and so that you will be able to follow along when you read the other tutorials.
-- Jay Reynolds Freeman (Jay_Reynolds_Freeman@mac.com)