2014-11-18-01-lambdaでクラス - 2
>> Site top >> weblog >> 月別アーカイブ >> 2014年11月のlog >> 2014-11-18-01-lambdaでクラス - 2
最終更新日付:2014/11/18 01:00:00
lambdaでクラス - 2
2014 年 11 月 18 日
最近、この log に何も書いていないな。以前のアレ、最近またイジり始めている。今回もその話。Common Lisp のマクロでもって C++ っぽいクラスを作れる CL-CLASS というライブラリ。
以前も書いた通り、これは Let Over Lambda の dlambda / plambda あたりをベースにしたクロージャベースのものだ。なので、メソッドの実行には(内部で)case / ecase を用いたメッセージディスパッチをしている。これが、まぁ当たり前なのだけどパフォーマンスに影響することには以前から気付いていた。特に、長大なループの中で何度もメソッド呼び出しやデータメンバアクセスをすると無駄が多い。
そこで、メソッドやデータメンバアクセスをクロージャ化して取得できる仕組みを追加した。そして、元々は記述を簡単にするためのマクロからそれを利用できるようにした。メソッドは以前からやっていたのだが、今回データメンバのアクセサでもやれるようにした。
では、どれくらい速くなったのか。適当ながら、以下のクラスで試してみよう。
(class:define test :members ((m-data :readwrite)) :constructors ((test () ((m-data 0)))))
まずは長大なループの中で毎回メンバアクセスをしてみよう。
(let ((obj (new test)) (val 0)) (time (dotimes (i 10000000) (setf val (class:member obj :m-data)) (setf (class:member obj :m-data) (1+ val))))) ;Evaluation took: ; 0.795 seconds of real time ; 0.795605 seconds of total run time (0.795605 user, 0.000000 system) ; [ Run times consist of 0.077 seconds GC time, and 0.719 seconds non-GC time. ] ; 100.13% CPU ; 1,902,061,963 processor cycles ; 1,280,016,000 bytes consed
で、同じことを、メンバアクセサとなるクロージャをループの外側で取得して使い回すようなコードに書き換えてみる。
(let ((obj (new test)) (val 0)) (time (class:with-all-members obj (dotimes (i 10000000) (setf val obj.m-data) (setf obj.m-data (1+ val)))))) ;Evaluation took: ; 0.218 seconds of real time ; 0.218401 seconds of total run time (0.218401 user, 0.000000 system) ; 100.00% CPU ; 525,264,256 processor cycles ; 0 bytes consed
うん、良好なようだ。class:with-all-members というのは暫定的な名前のマクロだけれど、これを使えばデータメンバには obj.m-data みたいな symbol-macrolet で、メソッド呼び出しは (obj->method param) みたいな macrolet でアクセスできる。実はこの with-all-members というマクロ、今日データメンバアクセスまで効率化させたことにより、結構な長さの展開形を出力するようになってしまった。しかしそれについてはまた日を改めるとしよう。
コメント
このページのタグ
Page tag : Common Lisp
Copyright(C) 2005-2021 project-enigma.
Generated by CL-PREFAB.