再挑戦
2023年の夏、マルチスレッドによる並列Lispに挑戦していました。一応は動作するようになったものの、期待していたほどの並列による高速化はできませんでした。それは逐次よりも遅くなってしまうのでした。2024年の春になり、今度はマルチプロセスで挑戦することにしました。
マルチプロセス
マルチスレッドではメモリ空間を共有していました。しかし、マルチプロセスではそれぞれのメモリ空間で独立しています。試しに手動で3つのEasy-Lisp処理系を立ち上げてそれぞれで竹内関数を実行させてみました。速度はそれぞれ逐次のときと変わりません。これなら並列を活かせそうです。
ChatGPTと相談しました。プロセス間でやりとりするにはどうしたらいいかな? ChatGPTはあれこれと提案してきました。それぞれの方法について勉強してみるとunixのforkとpipeを使うのが簡便そうでした。fork()で子Lispを起動させ、その入出力をパイプにつなぐ方法をとりました。標準入力はバッファリングされていることがわかりました。試行錯誤の末に独自にバッファリングすることで子Lispと親Lispでパイプによるプロセス間通信ができるようになりました。
並列構文
マルチスレッドの時と同様に次の並列構文を用意、実装しました。
- (mp-create n)
- (mp-close)
- (mp-call fun arg1 ... argn)
- (mp-exec arg1 ... argn)
- (mp-let forms body)
mp-createによりn個の子Lispを起動しておきます。call.exec.letはスレッド方式と同じ意味あいです。
たらい回し
竹内関数を並列実行させることに取り組みました。ここで使用したパソコンはインテルIcore7が積まれたWindowsマシンです。WSL2で動かしています。
(defun tarai* (x y z)
(if (<= x y)
y
(mp-call #'tarai* (tarai (- x 1) y z)
(tarai (- y 1) z x)
(tarai (- z 1) x y))))
(defun tarai (x y z)
(if (<= x y)
y
(tarai (tarai (- x 1) y z)
(tarai (- y 1) z x)
(tarai (- z 1) x y))))
インタプリタでの実行は下記のとおりです。
コンパイラ
さらにコンパイラを改良して並列構文もコンパイルできるようにしました。
考察
竹内関数は3つの引数から成ります。これを3つの子Lispで並列処理しています。それらの計算料は均等ではありません。このため3分の1にはなりません。最も計算料の多い引数の処理時間の影響を受けます。それにしても並列による効果が得られました。
展望
ver3.90をリリースし、当初の目標をほぼ達成しました。ver4.00にむけてさらに改良、バグ修正をしたいと思います。Githubにて公開しています。お気づきの点がありましたらIssuesにてご連絡をお願いいたします。