1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-12 06:41:13 +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)) (use-modules (ice-9 threads))
@end example @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 @deffn syntax parallel expr1 @dots{} exprN
Evaluate each @var{expr} expression in parallel, each in its own thread. Evaluate each @var{expr} expression in parallel, each in its own thread.
Return the results as a set of @var{N} multiple values 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. Mapping}), but make their @var{proc} calls in parallel.
@end deffn @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 @deffn {Scheme Procedure} n-par-map n proc lst1 @dots{} lstN
@deffnx {Scheme Procedure} n-par-for-each 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 Call @var{proc} on the elements of the given lists, in the same way as

View file

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

View file

@ -1,6 +1,6 @@
;;;; threads.test --- Tests for Guile threading. -*- scheme -*- ;;;; 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 ;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public ;;;; 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 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
(define-module (test-threads) (define-module (test-threads)
:use-module (ice-9 threads) #:use-module (ice-9 threads)
:use-module (test-suite lib)) #:use-module (system base compile)
#:use-module (test-suite lib))
(define (asyncs-still-working?) (define (asyncs-still-working?)
(let ((a #f)) (let ((a #f))
@ -70,6 +71,38 @@
(equal? y 2) (equal? y 2)
(equal? z 3)))))) (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 ;; n-par-for-each
;; ;;