性能的defclass类型信息

时间:2014-04-14 13:03:46

标签: performance common-lisp sbcl typing clos

在以下程序中,删除行

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

使用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)))

如果我每次使用arr插槽simple-array bit而不必声明let插槽,我怎样才能获得相同的性能优势?后者特别烦人,因为(据我所知)每次都需要通过(slot-value inst 'arr)或类似物引入绑定;我不能在我需要它的地方写{{1}}。

2 个答案:

答案 0 :(得分:5)

首先,这是一个特定于SBCL的问题,您可以在SBCL用户列表中获得更好的答案。不同的编译器会进行不同的优化,而且大多数都忽略了一些声明。

第二次,您应该让{-1}}绑定,因为您正在使用它两次。

第三次,如果您想避免let-bind,可以使用the

arr

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

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

答案 1 :(得分:4)

添加类型信息具有不同的效果,具体取决于您使用的编译器以及哪些优化级别有效。

对于优化编译器,它可能如下所示:

  • 没有信息:通用操作,合理快速
  • 类型声明可用:添加操作以在运行时检查此特定类型 - &gt;慢
  • 类型声明可用,高优化和低安全性:在运行时没有添加操作以进行类型检查,为此类型生成的专用代码 - &gt;可能更快

某些编译器也会忽略CLOS插槽的类型声明。如果他们不这样做,又有两种变体:1)安全意味着增加运行时检查; 2)低安全性和高速意味着产生专门指令

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