编译表达式比解释版本运行得慢得多

时间:2011-05-11 11:43:03

标签: c# performance jit precompiled

我有一个规则引擎,它支持两种操作模式:

  1. 编译成C#程序并链接到引擎
  2. 解析反向抛光基于堆栈的指令并解释
  3. 规则是带函数调用的简单算术表达式(max,min,sin,cos等)。

    我会假设编译版本(即#1)比解释版本(即#2)更快 - 事实上,这是编译模式的主要原因第一名。但是,我的速度测试显示不然。

    编译版

    Action<double>[] Rules = new[] { calc1, calc2, calc3 ... };
    double[] v = new double[...];   // Variables
    
    void calc1(double arg) { v[3]=v[12]+v[15]/v[20] };   // "x3=x12+x15/x20"
    void calc2(double arg) { ... };
       :
    // Start timer now
    Rules.AsParallel().ForAll(r => r(...));
    // End timer
    

    解释版

    Expression[] Rules = ...
    // Each rule is already parsed into an Expression object, which is a set of
    // reverse-polish stack-based instructions.
    // For example, "x3=x12+x15/x20" will be parsed to:
    //     [ Push(12), Push(15), Push(20), Divide(), Add() ]
    // Start timer now
    Rules.AsParallel().ForAll(r => r.Evaluate(...));
    // End timer
    

    这里,“Expression”是第三方库的一部分,它将一个简单的字符串解析为一组简单的反向抛光基于堆栈的指令,然后可以对其进行解释。 不是 LINQ中的表达式树对象 - 只是为了澄清。

    注意:不要担心并发性,因为在实际代码中,我按“层”对规则进行排序并按顺序计算层,每层只依赖于先前层中计算的值。两种模式都具有完全相同的层结构。

    结果

    令人震惊的是,解释版本比编译版本运行 MUCH 更快,平均为4倍!换句话说,编译版本需要0.3秒才能运行大约1,200条规则,而解释版本平均需要0.08-0.1秒。

    我的电脑是一款看似双核的Core2。

    我使用的是.NET 4.0,Visual Studio 10。

    在Debug或Release版本中,性能类似。

    我的问题

    导致编译模式显着减速的原因是什么?

    注意:我已经发布了一个可能的答案

1 个答案:

答案 0 :(得分:1)

.NET是一个JIT编译的环境,因此JIT编译的代码越多,它就越慢。可能是1,200个方法在执行时在运行时进行JIT编译,而在解释模式中只有解释器是JIT编译的一次。对于编译模式,我可能会在循环中看到额外的JIT时间。

实验:

  1. 运行每个模式5次(只是为了完成任何JIT编译和填充缓存)
  2. 时间50次,取平均值
  3. 结果:

    1. 编译模式:每次运行1.6毫秒
    2. 解释模式:每次运行5.3毫秒
    3. 观察:

      在编译模式的 FIRST 运行期间,似乎花费了大量时间。

      编译模式的 SECOND 运行速度与解释模式的速度相似。

      解释模式的运行次数不会显着加快。

      因此建议我的观点是规则代码在第一次运行期间是JIT编译的。