#:g1: pcallの紹介

Posted 2014-09-08 14:45:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の251日目です。

pcallとはなにか

 pcallは、Marijn Haverbeke氏作のCommon Lispの並列実行のライブラリです。

パッケージ情報

パッケージ名pcall
Quicklisp
Quickdocspcall | Quickdocs
CL Test Grid: ビルド状況pcall | CL Test Grid

インストール方法

(ql:quickload :pcall)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 pcallはスレッドプールを利用してスレッドを管理しています。使い勝手もシンプルで使い易い感じです。

(defun fib (n)
  (if (< n 2)
      n
      (+ (fib (- n 1)) (fib (- n 2)))))

(fib 40) ;=> 102334155 #|------------------------------------------------------------| Evaluation took: 1.958 seconds of real time 2.024000 seconds of total run time (2.024000 user, 0.000000 system) 103.37% CPU 6,448,324,307 processor cycles 0 bytes consed

Intel(R) Xeon(R) CPU E3-1230 v3 @ 3.30GHz |------------------------------------------------------------|#

(let ((f40 (pcall:pcall (lambda () (fib 40)))) (f39 (pcall:pcall (lambda () (fib 39)))) (f38 (pcall:pcall (lambda () (fib 38)))) (f37 (pcall:pcall (lambda () (fib 37))))) (+ (pcall:join f40) (pcall:join f39) (pcall:join f38) (pcall:join f37))) ;=> 228826127 #|------------------------------------------------------------| Evaluation took: 1.975 seconds of real time 4.504000 seconds of total run time (4.504000 user, 0.000000 system) 228.05% CPU 6,502,994,861 processor cycles 24,592 bytes consed

Intel(R) Xeon(R) CPU E3-1230 v3 @ 3.30GHz |------------------------------------------------------------|#

(pcall (lambda...の省略フォームとして、pexecがあります。

(let ((f40 (pcall:pexec (fib 40)))
      (f39 (pcall:pexec (fib 39)))
      (f38 (pcall:pexec (fib 38)))
      (f37 (pcall:pexec (fib 37))))
  (+ (pcall:join f40)
     (pcall:join f39)
     (pcall:join f38)
     (pcall:join f37)))
;=> 228826127
#|------------------------------------------------------------|
Evaluation took:
  1.968 seconds of real time
  5.072000 seconds of total run time (5.072000 user, 0.000000 system)
  257.72% CPU
  6,482,446,806 processor cycles
  33,344 bytes consed

Intel(R) Xeon(R) CPU E3-1230 v3 @ 3.30GHz |------------------------------------------------------------|#

さらに、pletというletと似た感じの並列実行のためのフォームがあります。

(pcall:plet ((f40 (fib 40))
             (f39 (fib 39))
             (f38 (fib 38))
             (f37 (fib 37)))
  (+ f40 f39 f38 f37))
;=> 228826127
#|------------------------------------------------------------|
Evaluation took:
  1.972 seconds of real time
  4.580000 seconds of total run time (4.580000 user, 0.000000 system)
  232.25% CPU
  6,495,339,957 processor cycles
  0 bytes consed

Intel(R) Xeon(R) CPU E3-1230 v3 @ 3.30GHz |------------------------------------------------------------|#

これは、symbol-macroletを利用したフォームに展開されます。

(LET ((#:F401235
       (PCALL:PEXEC
         (FIB 40)))
      (#:F391236
       (PCALL:PEXEC
         (FIB 39)))
      (#:F381237
       (PCALL:PEXEC
         (FIB 38)))
      (#:F371238
       (PCALL:PEXEC
         (FIB 37))))
  (SYMBOL-MACROLET ((F40 (PCALL:JOIN #:F401235))
                    (F39 (PCALL:JOIN #:F391236))
                    (F38 (PCALL:JOIN #:F381237))
                    (F37 (PCALL:JOIN #:F371238)))
    (+ F40 F39 F38 F37)))

 スレッドプールのサイズの取得と変更には、thread-pool-sizeを利用します。

(setf (pcall:thread-pool-size) 7)
;=>  NIL

(pcall:thread-pool-size)
;=>  7

また、局所的にスレッドプールを変更するためのwith-local-thread-poolというフォームも用意されています。

(pcall:with-local-thread-pool (:size 1)
  (pcall:plet ((f40 (fib 40))
               (f39 (fib 39))
               (f38 (fib 38))
               (f37 (fib 37))
               (f36 (fib 36))
               (f35 (fib 35))
               (f34 (fib 34)))
    (+ f40 f39 f38 f37 f36 f35 f34)))
;=> 258686831
#|------------------------------------------------------------|
Evaluation took:
  4.943 seconds of real time
  4.896000 seconds of total run time (4.896000 user, 0.000000 system)
  99.05% CPU
  16,273,648,911 processor cycles
  34,944 bytes consed

Intel(R) Xeon(R) CPU E3-1230 v3 @ 3.30GHz |------------------------------------------------------------|#

まとめ

 今回は、pcallを紹介してみました。
並列実行のライブラリも色々ありますが、pcallはシンプルにまとまっているので使い易そうですね。

comments powered by Disqus