考虑一下Chez Scheme代码:
(进口(chezscheme))
(定义(list-enumerate ls val proc)
(让循环((ls ls)(返回?#f)(val val))
(如果(或(null?ls)
返回?)
值
(值调用(lambda()(proc val(car ls)))
(lambda(返回?val)
(循环(cdr ls)return?val))))))
(定义(list-index ls proc)
(列表枚举ls
0
(lambda(i elt)
(如果(proc elt)
(值#t i)
(值#f(+ i 1))))))
(定义n 100000)
(定义数据(iota n))
(时间(列表索引数据(lambda(elt)(= elt(-n 1)))))
运行:
〜$ scheme-脚本〜/scratch/_list-enumerate-allocation-test-chez-a.sps
(时间(列表索引数据...))
没有收藏
经过3 ms的cpu时间
实时经过4毫秒
分配了8个字节
哇,它报告只分配了8个字节。
让我们使用--program
选项而不是--script
再次运行它:
〜$ scheme-程序〜/scratch/_list-enumerate-allocation-test-chez-a.sps
(时间(列表索引数据...))
没有收藏
经过3 ms的cpu时间
实时经过3毫秒
分配了800000字节
Yikes,分配了800000字节。
有什么区别?
埃德
最佳答案
这是肯特·迪布维格(Kent Dybvig)的回应:
这是一个有趣的问题。
与--script(使用REPL语义)一起运行时,变量
脚本中定义的变量(例如list-enumerate和list-index)是可变的,
这会妨碍过程内的优化,包括内联。什么时候
使用--program运行,但是变量是不可变的,这允许
过程间优化。
在这种情况下,--program允许编译器内联列表枚举到
list-index的主体,反过来又在list-index的lambda表达式中
body 变成列表枚举的 body 。最终结果是有条件的
带有值的调用生产者表达式中的表达式。这引起
编译器为使用者创建一个闭包,以避免代码
沿条件的then和else分支重复。这
每次通过list-enumerate的循环创建闭包,导致
额外的分配开销。这就是优化经常进行的方式。
通常,您赢了,但有时却输了。总的来说,好消息是
好处甚至超出了您的费用,即使在您的程序中也是如此。我把电话打到
在循环中列出列表索引(修改后的代码在下面),发现
--program,代码运行速度提高了约30%。
肯特郡
(进口(chezscheme))
(定义(list-enumerate ls val proc)
(让循环((ls ls)(返回?#f)(val val))
(如果(或(null?ls)
返回?)
值
(值调用(lambda()(proc val(car ls)))
(lambda(返回?val)
(循环(cdr ls)return?val))))))
(定义(list-index ls proc)
(列表枚举ls
0
(lambda(i elt)
(如果(proc elt)
(值#t i)
(值#f(+ i 1))))))
(定义n 100000)
(定义数据(时间(iota n)))
(让 ()
(定义Runalot
(lambda(我重击)
(让循环([i i])
(让[[x(thunk)])
(如果(fx = i 1)
X
(循环(fx- i 1))))))))
(时间
(runalot 1000
(lambda()
(列表索引数据(lambda(elt)(= elt(-n 1)))))))
关于scheme - Chez方案分配: --program vs --script,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2378743/