5

在以下程序中,删除该行

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

使用 SBCL 使运行时间增加了 3 倍以上。另一方面,defclass宏 via中给出的类型信息似乎对性能没有影响。: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插槽 a ?simple-array bit后者特别烦人,因为(据我所知)let每次都需要通过或类似方式引入绑定;我不能只写(slot-value inst 'arr)在我需要的地方。

4

2 回答 2

5

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

其次,你应该 let-bindarr因为你使用了两次。

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

(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 忽略了槽类型声明。

于 2014-04-14T13:52:46.087 回答
4

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

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

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

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

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

于 2014-04-14T14:10:00.853 回答