Corrections to the guide's places entry
This commit is contained in:
parent
a6b4b42982
commit
cf772ceebd
|
@ -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 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))
|
||||
(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.
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user