如何加快Common Lisp`IF`语句的编译?

时间:2018-09-12 10:07:13

标签: performance if-statement common-lisp runtime-compilation clozure-cl

我有一个系统,该系统生成决策树并将其转换为嵌套的Common Lisp if语句,并带有谓词,该谓词检查变量值是>=还是<=给定整数,例如

(LAMBDA (V1 V2)
  (IF (>= V1 2)
      (IF (<= V1 3)
          (IF (<= V2 3)
              (IF (>= V2 2) 16 (IF (>= V2 1) 6 0))
            (IF (<= V2 4) 10 0))
        (IF (<= V1 4)
            (IF (>= V2 1) (IF (<= V2 3) 6 0) 0)
          0))
    (IF (>= V1 1)
        (IF (>= V2 2) (IF (<= V2 4) 10 0) 0)
      0)))

然后,我使用eval来编译Lisp代码,从而产生比解释原始决策树要快得多的函数。但是,此编译步骤花费了惊人的长时间:具有5000个嵌套ifs的函数要花一分钟多的时间才能编译(在powerbook上的Clozure Common Lisp中),即使生成if语句大约需要100毫秒。为什么这么简单的结构要花这么长时间?我可以做些什么来大大加快它的速度,也许可以声明一下?非常感谢您提供的任何提示。

2 个答案:

答案 0 :(得分:6)

用于编译函数的实际可移植函数称为COMPILE

您可以告诉Common Lisp编译器通过降低optimizespeedspacedebug的{​​{1}}质量来减少工作量-是否具有任何影响都取决于实施。

Clozure CL编译器通常不是最聪明的编译器,但是相对较快。通常,我认为编译器维护人员可能会为您提供更多有关如何加快编译速度的提示。通常我会找三个

  1. 告诉编译器要做更少的工作:没有类型推断,没有代码优化,没有生成调试信息,没有节省空间,...
  2. 如果有必要告诉编译器它必须要推断的内容-例如,而不是由编译器进行类型推断,请在代码生成期间声明所有类型。但这意味着您实际上需要从类型声明中获得一些优势,例如提高运行时安全性或代码优化。
  3. 编译器本身可能会有速度上的损失,这取决于源代码的大小。例如,如果是二次方,则如果我们将代码大小加倍,则编译时间将增加四倍。只有编译器维护人员才知道在这种情况下该怎么做-也许他们将需要实现更有效的数据结构或类似结构。...

下一个选项是使用Lisp解释器。通常,它们的定义时间开销很小-但是代码通常在运行时运行慢得多。在某些问题域中,可以采用一种混合方法:编译不经常更改的代码并解释不经常更改的代码。

答案 1 :(得分:4)

您当然可以(declare (optimize (compilation-speed 3))),并且可能会降低其他品质(请参见http://clhs.lisp.se/Body/d_optimi.htm#optimize)。

但是,我猜编译缓慢是由编译器进行的优化引起的,因此执行时的结果似乎不太快。但也许不是,您必须进行试验。

我还会考虑使用域知识可以进行哪些优化。提示也可能来自分析您生成的函数上的disassemble的输出。

最后,如果不同值的数量不太大,也许您可​​以将决策树转换为查找表。