2010-03-04 56 views
4

考慮的Chez Scheme這段代碼:切斯計劃分配:--program VS --script

 
(import (chezscheme)) 

(define (list-enumerate ls val proc) 
    (let loop ((ls ls) (return? #f) (val val)) 
    (if (or (null? ls) 
      return?) 
     val 
     (call-with-values (lambda() (proc val (car ls))) 
      (lambda (return? val) 
      (loop (cdr ls) return? val)))))) 

(define (list-index ls proc) 
    (list-enumerate ls 
        0 
        (lambda (i elt) 
        (if (proc elt) 
         (values #t i) 
         (values #f (+ i 1)))))) 

(define n 100000) 

(define data (iota n)) 

(time (list-index data (lambda (elt) (= elt (- n 1))))) 

運行:

 
~ $ scheme --script ~/scratch/_list-enumerate-allocation-test-chez-a.sps 
(time (list-index data ...)) 
    no collections 
    3 ms elapsed cpu time 
    4 ms elapsed real time 
    8 bytes allocated 

哇,它報告說,只有8個字節被分配。

讓我們來運行它再次使用--program選項,而不是--script

 
~ $ scheme --program ~/scratch/_list-enumerate-allocation-test-chez-a.sps 
(time (list-index data ...)) 
    no collections 
    3 ms elapsed cpu time 
    3 ms elapsed real time 
    800000 bytes allocated 

哎呀,分配800000個字節。

有什麼區別?

埃德

回答

4

這裏的響應肯特Dybvig一張紙條:


這是一個有趣的問題。

當與--script,它使用REPL語義,變量 在腳本中定義,如表枚舉和列表索引運行,是可變的, 抑制間優化,包括內聯。但是,當 以--program運行時,變量是不可變的,這允許進程間優化。

在這種情況下,--program允許編譯器內聯列表枚舉到 列表索引的身體和在轉彎列表索引的 體內lambda表達式成列表枚舉的屍體。最終結果是call-with-values生產者表達式中的條件 表達式。這會導致編譯器爲消費者創建閉包,以避免沿着條件的then和else分支複製代碼 。這個 閉包每次都通過list-enumerate的循環被創建,導致 額外的分配開銷。這是優化經常發生的方式。 大部分你贏了,但有時你輸了。總的來說,好消息是,即使在您的計劃中,他的成本也會超出其成本。我把呼叫列表索引放在一個循環中(修改後的代碼如下),並發現用 - 程序,代碼運行速度提高了大約30%。

肯特


 
(import (chezscheme)) 

(define (list-enumerate ls val proc) 
    (let loop ((ls ls) (return? #f) (val val)) 
    (if (or (null? ls) 
      return?) 
     val 
     (call-with-values (lambda() (proc val (car ls))) 
      (lambda (return? val) 
      (loop (cdr ls) return? val)))))) 

(define (list-index ls proc) 
    (list-enumerate ls 
        0 
        (lambda (i elt) 
        (if (proc elt) 
         (values #t i) 
         (values #f (+ i 1)))))) 

(define n 100000) 

(define data (time (iota n))) 

(let() 
(define runalot 
    (lambda (i thunk) 
    (let loop ([i i]) 
     (let ([x (thunk)]) 
     (if (fx= i 1) 
      x 
      (loop (fx- i 1))))))) 

(time 
    (runalot 1000 
    (lambda() 
     (list-index data (lambda (elt) (= elt (- n 1))))))))