#:g1: メソッドコンビネーションで並列実行

Posted 2018-12-15 21:45:07 GMT

Lisp メソッドコンビネーション Advent Calendar 2018 16日目 》

メソッドコンビネーションは、メソッドの集合をあるコンビネーションで実行することなので並列実行も範疇に入ると思われます。

メソッドコンビネーションで並列実行の例は、そこそこあるだろうと思ってネットをしばらく検索してみましたが、どうやらあまり試してみた例はないようです。

NetCLOSの構文の見た目が、メソッドコンビネーションっぽかったのでソースを確認してみましたが、残念ながら、並列実行のパターンに直接メソッドコンビネーションを活用している訳ではない様子(メッセージ送信のシークエンスに活用してはいるようです)
ちなみに、NetCLOSは、ABCL/1にインスパイアされたアクターベースの並列オブジェクト指向なCLOSのネットワーク拡張です。

メソッドコンビネーションと素朴な並列実行

非常に素朴ですが、各メソッドをスレッドに分配して全部実行してジョインというのは簡単に書けます。
コンビネーションとしては、prognメソッドコンビネーションが並列に実行される、という感じでしょうか。

(define-method-combination par ()
  ((ms (:name . *)))
  (let ((ths (loop :for () :in ms 
                   :collect (gensym "thread-"))))
    `(let (,@(mapcar (lambda (m th)
                       `(,th (bt:make-thread 
                              (lambda ()
                                (call-method ,m))
                              :name ,(second (method-qualifiers m)))))
                     ms
                     ths))
       (let ((ans (list ,@ths)))
         (declare (dynamic-extent ans))
         (values-list (mapcar #'bt:join-thread ans))))))

(defgeneric para (x &optional out)
  (:method-combination par))

(defmethod para :name "foo" (x &optional out) (format out "~&start A ...~%") (sleep 3) (format out "~&... end A~%"))

(defmethod para :name "bar" (x &optional out) (format out "~&start B ...~%") (sleep 5) (format out "~&... end B~%"))

(mc-expand #'para 'par nil 3)(let ((#:|thread-181190|
       (bt:make-thread (lambda ()
                         (call-method #<standard-method para (:name "bar") (t) 40303B7D63>))
                       :name "bar"))
      (#:|thread-181191|
       (bt:make-thread (lambda ()
                         (call-method #<standard-method para (:name "foo") (t) 40303A6263>))
                       :name "foo")))
  (let ((ans (list #:|thread-181190| #:|thread-181191|)))
    (declare (dynamic-extent ans))
    (values-list (mapcar #'bt:join-thread ans))))

(para 3 #.*standard-output*)
start A ...
start B ...
... end A
... end B
→ nil
   nil

上記では、ジョインする手間が省けている程度ですが、やりようによっては役に立つものができるかもしれません……。


HTML generated by 3bmd in LispWorks 7.0.0

comments powered by Disqus