1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-10 22:10:21 +02:00

Implement `(ice-9 threads)' high-level constructs in terms of futures.

* module/ice-9/threads.scm (parallel, par-mapper): Rewrite in terms of
  `future' and `touch'.

* test-suite/tests/threads.test ("par-map", "par-for-each"): New test
  prefixes.

* doc/ref/api-scheduling.texi (Parallel Forms): Add cross-ref to
  futures.  Recommend against the `n-' variants.
This commit is contained in:
Ludovic Courtès 2010-12-16 23:44:55 +01:00
parent 6c17f7bd71
commit c21a5ddcaf
3 changed files with 69 additions and 21 deletions

View file

@ -904,6 +904,11 @@ The functions described in this section are available from
(use-modules (ice-9 threads))
@end example
They provide high-level parallel constructs. The following functions
are implemented in terms of futures (@pxref{Futures}). Thus they are
relatively cheap as they re-use existing threads, and portable, since
they automatically use one thread per available CPU core.
@deffn syntax parallel expr1 @dots{} exprN
Evaluate each @var{expr} expression in parallel, each in its own thread.
Return the results as a set of @var{N} multiple values
@ -935,6 +940,16 @@ These functions are like @code{map} and @code{for-each} (@pxref{List
Mapping}), but make their @var{proc} calls in parallel.
@end deffn
Unlike those above, the functions described below take a number of
threads as an argument. This makes them inherently non-portable since
the specified number of threads may differ from the number of available
CPU cores as returned by @code{current-processor-count}
(@pxref{Processes}). In addition, these functions create the specified
number of threads when they are called and terminate them upon
completion, which makes them quite expensive.
Therefore, they should be avoided.
@deffn {Scheme Procedure} n-par-map n proc lst1 @dots{} lstN
@deffnx {Scheme Procedure} n-par-for-each n proc lst1 @dots{} lstN
Call @var{proc} on the elements of the given lists, in the same way as

View file

@ -32,19 +32,20 @@
;;; Code:
(define-module (ice-9 threads)
:export (begin-thread
parallel
letpar
make-thread
with-mutex
monitor
#:use-module (ice-9 futures)
#:export (begin-thread
parallel
letpar
make-thread
with-mutex
monitor
par-map
par-for-each
n-par-map
n-par-for-each
n-for-each-par-map
%thread-handler))
par-map
par-for-each
n-par-map
n-par-for-each
n-for-each-par-map
%thread-handler))
@ -62,10 +63,9 @@
(syntax-case x ()
((_ e0 ...)
(with-syntax (((tmp0 ...) (generate-temporaries (syntax (e0 ...)))))
(syntax
(let ((tmp0 (begin-thread e0))
...)
(values (join-thread tmp0) ...))))))))
#'(let ((tmp0 (future e0))
...)
(values (touch tmp0) ...)))))))
(define-syntax letpar
(syntax-rules ()
@ -99,10 +99,10 @@
(define (par-mapper mapper)
(lambda (proc . arglists)
(mapper join-thread
(mapper touch
(apply map
(lambda args
(begin-thread (apply proc args)))
(future (apply proc args)))
arglists))))
(define par-map (par-mapper map))

View file

@ -1,6 +1,6 @@
;;;; threads.test --- Tests for Guile threading. -*- scheme -*-
;;;;
;;;; Copyright 2003, 2006, 2007, 2009 Free Software Foundation, Inc.
;;;; Copyright 2003, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
;;;;
;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
@ -17,8 +17,9 @@
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
(define-module (test-threads)
:use-module (ice-9 threads)
:use-module (test-suite lib))
#:use-module (ice-9 threads)
#:use-module (system base compile)
#:use-module (test-suite lib))
(define (asyncs-still-working?)
(let ((a #f))
@ -70,6 +71,38 @@
(equal? y 2)
(equal? z 3))))))
;;
;; par-map
;;
(with-test-prefix "par-map"
(pass-if "simple"
(compile '(letrec ((fibo (lambda (n)
(if (<= n 1)
n
(+ (fibo (- n 1))
(fibo (- n 2)))))))
(equal? (par-map fibo (iota 13))
(map fibo (iota 13))))
#:to 'value
#:env (current-module))))
;;
;; par-for-each
;;
(with-test-prefix "par-for-each"
(pass-if "simple"
(compile '(let ((v (make-vector 6 #f)))
(par-for-each (lambda (n)
(vector-set! v n n))
(iota 6))
(equal? v (list->vector (iota 6))))
#:to 'value
#:env (current-module))))
;;
;; n-par-for-each
;;