Chez Scheme分配: - program vs --script

时间:2010-03-04 11:13:19

标签: scheme chez-scheme

考虑一下Chez Scheme代码:

(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

Yikes,分配了800000个字节。

有什么区别?

1 个答案:

答案 0 :(得分:4)

以下是Kent Dybvig的回复:


这是一个有趣的问题。

使用--script运行时,它使用REPL语义,变量 在脚本中定义,如list-enumerate和list-index,是可变的, 这抑制了过程间优化,包括内联。什么时候 然而,运行--program,变量是不可变的,允许 过程间优化。

在这种情况下, - program允许编译器内联list-enumerate list-index的主体,反过来又是list-index中的lambda表达式 body进入list-enumerate的主体。最终结果是有条件的 call-with-values生成器表达式中的表达式。这导致 编译器为消费者创建一个闭包,以避免代码 沿条件的then和else分支重复。这个 每次通过list-enumerate的循环创建闭包,从而产生 额外的分配开销。这就是优化经常发生的方式。 大多数情况下你赢了,但有时你输了。总的来说,好消息是 即使在您的计划中,也可以减轻他的成本。我打电话给 循环中的list-index(修改后的代码在下面)并发现那个 - 程序,代码运行速度提高了约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))))))))