在以下程序中,删除行
(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}}。
答案 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)
添加类型信息具有不同的效果,具体取决于您使用的编译器以及哪些优化级别有效。
对于优化编译器,它可能如下所示:
某些编译器也会忽略CLOS插槽的类型声明。如果他们不这样做,又有两种变体:1)安全意味着增加运行时检查; 2)低安全性和高速意味着产生专门指令
总结:由于添加了类型检查,类型声明可能会增加运行时间开销并具有高安全性。专业数据类型不一定更快,安全性低,优化程度高。