Las*_*ann 5 performance sbcl typing common-lisp clos
在以下程序中,删除该行
(declare (type (simple-array bit) arr))
Run Code Online (Sandbox Code Playgroud)
使用SBCL使运行时间增加3倍以上.另一方面,defclass宏通过中给出的类型信息:type似乎对性能没有影响.
(defclass class-1 () ((arr :type (simple-array bit))))
(defun sample (inst)
(declare (type class-1 inst))
(let ((arr (slot-value inst 'arr)))
(declare (type (simple-array bit) arr)) ;; 3x running time without
(map-into arr #'(lambda (dummy) (if (< (random 1.0) 0.5) 0 1)) arr)))
(let ((inst (make-instance 'class-1)))
(setf (slot-value inst 'arr) (make-array 10000 :element-type 'bit))
(loop for i from 1 to 10000 do (sample inst)))
Run Code Online (Sandbox Code Playgroud)
如何在不必每次使用时都声明arr插槽的情况下获得相同的性能优势simple-array bit?后者特别烦人,因为(据我所知)let每次都需要引入绑定通道或类似物; 我不能只(slot-value inst 'arr)在我需要它的地方写字.
首先,这是一个特定于SBCL的问题,您可能会在SBCL用户列表上得到更好的答案.不同的编译器执行不同的优化,并且大多数忽略至少一些声明.
其次,你应该让绑定,arr因为你使用它两次.
第三,the如果你想避免let-bind ,你可以使用:
(the (simple-array bit) (slot-value inst 'arr))
Run Code Online (Sandbox Code Playgroud)
第四,如果您希望编译器推断类型,请使用特定的读取器而不是slot-value:
(defclass c () ((arr :type (simple-array bit) :reader c-arr)))
(defun sample (inst)
(declare (type class-1 inst))
(let ((arr (c-arr inst)))
(map-into arr #'(lambda (dummy) (random 2)) arr)))
Run Code Online (Sandbox Code Playgroud)
c-arr 应该允许编译器更容易推断值类型,但是(正如您自己发现的那样!)您可能需要声明其返回类型:
(declaim (ftype (function (c) (simple-array bit)) c-arr))
Run Code Online (Sandbox Code Playgroud)
显然,原因是SBCL忽略了插槽类型声明.