From cf772ceebdba7c63bbbbebd84900696a64982a5c Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Mon, 5 Sep 2011 18:10:00 -0600 Subject: [PATCH] Corrections to the guide's places entry --- collects/scribblings/guide/places.scrbl | 111 ++++++++++++------------ 1 file changed, 57 insertions(+), 54 deletions(-) diff --git a/collects/scribblings/guide/places.scrbl b/collects/scribblings/guide/places.scrbl index 5d6dbce21e..f0bafd87e5 100644 --- a/collects/scribblings/guide/places.scrbl +++ b/collects/scribblings/guide/places.scrbl @@ -6,16 +6,18 @@ The @racketmodname[racket/place] library provides support for performance improvement through parallelism with the @racket[place] -form. Two places communicate using @racket[place-channel-put] and -@racket[place-channel-get] functions. Places contains the full -expressive power of the Racket language. However, the places design -restricts both the methods of inter-place communication and the type -of values permitted inside communication messages. +form. The @racket[place] form creates a @deftech{place}, which is +effectively a new Racket instance that can run in parallel to other +places, including the initial place. The full power of the Racket +language is available at each place, but places can communicate only +through message passing---using the @racket[place-channel-put] and +@racket[place-channel-get] functions on a limited set of +values---which helps ensure the safety and independence of parallel +computations. -The @racket[place] form spawns a new pristine racket execution -context, which the OS can schedule on any available processor. As a -starting example, the racket program below uses a place to determine -whether any number in the list has a double that is also in the list: +As a starting example, the racket program below uses a @tech{place} to +determine whether any number in the list has a double that is also in +the list: @codeblock{ #lang racket @@ -28,66 +30,67 @@ whether any number in the list has a double that is also in the list: (= i2 (* 2 i))))) (define (main) - (define p (place ch - (define l (place-channel-get ch)) - (define l-double? (any-double? l)) - (place-channel-put ch l-double?))) + (define p + (place ch + (define l (place-channel-get ch)) + (define l-double? (any-double? l)) + (place-channel-put ch l-double?))) (place-channel-put p (list 1 2 4 8)) - (printf "Has double? ~a\n" (place-channel-get p)) - (place-wait p)) + (begin0 + (place-channel-get p)) + (place-wait p)) } -The first argument to the place form is an identifier, which the -@racket[place] form binds to an initial place-channel. The remaining -argument expressions form the body of the @racket[place] form. The -body expressions use the initial place-channel to communicate with the -place which spawned the new place. +The identifier @racket[ch] after @racket[place] is bound to a @deftech{place +channel}. The remaining body expressions within the @racket[place] form +are evaluated in a new place, and the body expressions use @racket[ch] +to communicate with the place that spawned the new place. -In the example above, the place form has a body of three expressions. -The first receives a list of numbers over the initial place-channel -(@racket[ch]) and binds the list to @racket[l]. The second body -expression calls any-double? on the list and binds the result to -@racket[l-double?]. The last body expression sends the -@racket[l-double?] result back to the invoking place over the -@racket[ch] place-channel. +In the body of the @racket[place] form above, the new place receives a +list of numbers over @racket[ch] and binds the list to @racket[l]. It +then calls @racket[any-double?] on the list and binds the result to +@racket[l-double?]. The final body expression sends the +@racket[l-double?] result back to the original place over @racket[ch]. -The macro that implements the @racket[place] form performs two actions with -subtle consequences. First, it lifts the place body to an anonymous -module-scope function. This has the consequence that any function -referred to by the place body must be defined at module-scope. Second, -the place form expands into a @racket[dynamic-place] call, which -@racket[dynamic-require]s the current module in a newly created place. -@margin-note{When using places inside DrRacket, the module containg -place code must be saved to a file before it will execute.} -As part of the @racket[dynamic-require] the current module body is -evaluated in the new place. The consequence of this second action is -that places forms must not be called at module-scope or indirectly by -functions which are invoked at module scope. Both of these errors are -demonstrated in the code bellow. Failing to follow this precaution -will result in an infinite spawning of places as each spawned place -evaluates the module body and spawns an additional place. +In DrRacket, after saving and running the above program, evaluate +@racket[(main)] in the interactions window to create the new +place. @margin-note*{When using @tech{places} inside DrRacket, the +module containg place code must be saved to a file before it will +execute.} Alternatively, save the program as @filepath{double.rkt} +and run from a command line with + +@commandline{racket -tm double.rkt} + +where the @Flag{t} flag tells @exec{racket} to load the +@tt{double.rkt} module, the @Flag{m} flag calls the exported +@racket[main] function, and @Flag{tm} combines the two flags. + +The @racket[place] form has two subtle features. First, it lifts the +@racket[place] body to an anonymous, module-level function. This +lifting means that any binding referenced by the @racket[place] body +must be available in the module's top level. Second, the +@racket[place] form @racket[dynamic-require]s the enclosing module in +a newly created place. As part of the @racket[dynamic-require], the +current module body is evaluated in the new place. The consequence of +this second feature is that @racket[place] should appear immediately +in a module or in a function that is called in a module's top level; +otherwise, invoking the module will invoke the same module in a new +place, and so on, triggering a cascade of place creations that will +soon exhaust memory. @codeblock{ #lang racket (provide main) -; do not do this -(define p (place ch - (place-channel-get ch))) +; Don't do this! +(define p (place ch (place-channel-get ch))) (define (indirect-place-invocation) - (define p2 (place ch - (place-channel-get ch)))) + (define p2 (place ch (place-channel-get ch)))) - -; do not do this either +; Don't do this, either! (indirect-place-invocation) } -The example above is executed by running @exec{racket -tm double.rkt} -from the command line. The @Flag{t} tells racket to load the -@tt{double.rkt} module. The @Flag{m} instructs racket to run the -@racket[main] module. -