2014-04-14 40 views
5

在下面的程序,除去線性能defclass類型信息

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

使得由多於一個因素的運行時間3增加,使用SBCL。 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)

回答

5

第一個,這是SBCL特有的問題,您可能會在SBCL用戶列表中得到更好的答案。不同的編譯器會做不同的優化,而且大多數忽略至少一些聲明。

第二個,你應該讓 - 綁定arr因爲你使用它兩次。

,你可以使用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忽略插槽類型聲明。

+0

使用讀卡器是一個好主意,但它不直接爲我工作。然而,使用你的類和函數名的是一個讀者加上以下內容:'(declaim(ftype(function((c))(simple-array bit))c-arr))'。有了這個,甚至可以省略':type',以及'(declare(type class-1 inst))'。 –

+0

它可能應該是'(declaim(ftype(function(c)(simple-array bit))c-arr))'。兩者都似乎工作,我不知道爲什麼。以前沒有使用過這種形式。 –

4

根據您使用的編譯器和哪些優化級別生效,添加類型信息具有不同的效果。

對於優化編譯器它可能是這樣的:

  • 沒有信息:通用操作,相當快
  • 類型聲明可供選擇:添加操作運行時檢查這種特定類型 - >慢
  • 類型聲明可用,高優化和低安全性:在運行時沒有增加類型檢查操作,爲此類型生成專用代碼 - > POSSIBLY FASTER

某些編譯器也會忽略CLOS插槽的類型聲明。如果它們不匹配,有再次兩個變體:1)安全裝置加入的運行時檢查和2)低的安全性和高速裝置專用指令生成

總結:類型聲明可以以高安全性由於添加類型添加的運行時開銷檢查。專業數據類型不一定更快,安全性較低,優化程度較高。