#lang scribble/doc @(require "mz.ss" (for-label racket/future)) @(define future-eval (make-base-eval)) @(interaction-eval #:eval future-eval (require racket/future)) @title[#:tag "futures"]{Futures} @guideintro["effective-futures"]{futures} @note-lib[racket/future] @margin-note{Currently, parallel support for @racket[future] is enabled by default for Windows, Linux x86/x86_64, and Mac OS X x86/x86_64. To enable support for other platforms, use @DFlag{enable-futures} with @exec{configure} when building Racket.} The @racket[future] and @racket[touch] functions from @racketmodname[racket/future] provide access to parallelism as supported by the hardware and operating system. In contrast to @racket[thread], which provides concurrency for arbitrary computations without parallelism, @racket[future] provides parallelism for limited computations. A future executes its work in parallel (assuming that support for parallelism is available) until it detects an attempt to perform an operation that is too complex for the system to run safely in parallel. Similarly, work in a future is suspended if it depends in some way on the current continuation, such as raising an exception. A suspended computation for a future is resumed when @racket[touch] is applied to the future. ``Safe'' parallel execution of a future means that all operations provided by the system must be able to enforce contracts and produce results as documented. ``Safe'' does not preclude concurrent access to mutable data that is visible in the program. For example, a computation in a future might use @racket[set!] to modify a shared variable, in which case concurrent assignment to the variable can be visible in other futures and threads. Furthermore, guarantees about the visibility of effects and ordering are determined by the operating system and hardware---which rarely support, for example, the guarantee of sequential consistency that is provided for @racket[thread]-based concurrency. At the same time, operations that seem obviously safe may have a complex enough implementation internally that they cannot run in parallel. See also @guidesecref["effective-futures"] in @|Guide|. A future never runs in parallel if all of the @tech{custodians} that allow its creating thread to run are shut down. Such futures can execute through a call to @racket[touch], however. @deftogether[( @defproc[(future [thunk (-> any)]) future?] @defproc[(touch [f future?]) any] )]{ The @racket[future] procedure returns a future value that encapsulates @racket[thunk]. The @racket[touch] function forces the evaluation of the @racket[thunk] inside the given future, returning the values produced by @racket[thunk]. After @racket[touch] forces the evaluation of a @racket[thunk], the resulting values are retained by the future in place of @racket[thunk], and additional @racket[touch]es of the future return those values. Between a call to @racket[future] and @racket[touch] for a given future, the given @racket[thunk] may run speculatively in parallel to other computations, as described above. @interaction[ #:eval future-eval (let ([f (future (lambda () (+ 1 2)))]) (list (+ 3 4) (touch f))) ]} @defproc[(current-future) (or/c #f future?)]{ Returns the descriptor of the future whose thunk execution is the current continuation. If a future thunk itself uses @racket[touch], future-thunk executions can be nested, in which case the descriptor of the most immediately executing future is returned. If the current continuation is not a future-thunk execution, the result is @racket[#f]. } @defproc[(future? [v any/c]) boolean?]{ Returns @racket[#t] if @racket[v] is a future value, @racket[#f] otherwise. } @defproc[(processor-count) exact-positive-integer?]{ Returns the number of parallel computation units (e.g., processors or cores) that are available on the current machine. } @defproc[(make-fsemaphore [init exact-nonnegative-integer?]) fsemaphore?]{ Creates and returns a new @deftech{future semaphore} with the counter initially set to @racket[init]. A future semaphore is similar to a plain @tech{semaphore}, but future-semaphore operations can be performed safely in parallel (to synchronize parallel computations). In contrast, operations on plain @tech{semaphores} are not safe to perform in parallel, and they therefore prevent a computation from continuing in parallel. } @defproc[(fsemaphore? [v any/c]) boolean?]{ Returns @racket[#t] if @racket[v] is an @tech{future semaphore} value, @racket[#f] otherwise. } @defproc[(fsemaphore-post [fsema fsemaphore?]) void?]{ Increments the @tech{future semaphore}'s internal counter and returns @|void-const|. } @defproc[(fsemaphore-wait [fsema fsemaphore?]) void?]{ Blocks until the internal counter for @racket[fsema] is non-zero. When the counter is non-zero, it is decremented and @racket[fsemaphore-wait] returns @|void-const|. } @defproc[(fsemaphore-try-wait? [fsema fsemaphore?]) boolean?]{ Like @racket[fsemaphore-wait], but @racket[fsemaphore-try-wait?] never blocks execution. If @racket[fsema]'s internal counter is zero, @racket[fsemaphore-try-wait?] returns @racket[#f] immediately without decrementing the counter. If @racket[fsema]'s counter is positive, it is decremented and @racket[#t] is returned. } @defproc[(fsemaphore-count [fsema fsemaphore?]) exact-nonnegative-integer?]{ Returns @racket[fsema]'s current internal counter value. } @; ---------------------------------------------------------------------- @close-eval[future-eval]