性能的defclass类型信息

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)在我需要它的地方写字.

sds*_*sds 5

首先,这是一个特定于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忽略了插槽类型声明.