用于性能的公共lisp-defclass类型信息



在以下程序中,删除行

    (declare (type (simple-array bit) arr))

使用SBCL使运行时间增加了3倍以上。另一方面,通过:typedefclass宏中给出的类型信息似乎对性能没有影响。

(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)))

如果每次使用arr插槽时都不必将其声明为simple-array bit,我如何才能获得相同的性能优势?后者特别令人讨厌,因为(据我所知)每次都需要通过let或类似的方式引入绑定;我不能只在需要的地方写(slot-value inst 'arr)

首先这是一个SBCL特定的问题,您可能会在SBCL用户列表中得到更好的答案。不同的编译器执行不同的优化,并且大多数编译器至少忽略一些声明。

第二个,您应该让绑定arr,因为您要使用它两次。

第三,如果您想避免let绑定,可以使用the

(the (simple-array bit) (slot-value inst 'arr))

第四个,如果希望编译器推断类型,请使用特定的读取器,而不是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)))

c-arr应该允许编译器更容易地推断值类型,但(正如您自己发现的那样!)您可能需要声明其返回类型:

(declaim (ftype (function (c) (simple-array bit)) c-arr))

原因显然是SBCL忽略了槽类型声明。

添加类型信息会产生不同的效果,这取决于您使用的编译器和有效的优化级别。

对于优化编译器来说,它可能看起来像这样:

  • 无信息:通用操作,速度相当快
  • 可用的类型声明:添加了在运行时检查此特定类型的操作->较慢
  • 类型声明可用,高度优化和低安全性:运行时不添加类型检查操作,为该类型生成专用代码->可能更快

一些编译器还忽略CLOS插槽的类型声明。如果没有,又有两种变体:1)安全意味着增加运行时检查;2)低安全和高速意味着生成的专用指令

摘要:由于添加了类型检查,类型声明可能会增加具有高安全性的运行时开销。专门的数据类型不一定速度更快,安全性低,优化程度高。

相关内容

  • 没有找到相关文章

最新更新