2つの操作モードをサポートするルールエンジンがあります。
- C#プログラムへのコンパイルとエンジンへのリンク
- 逆ポーランドスタックベースの命令に解析し、解釈します
ルールは、関数呼び出し(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の式ツリーオブジェクトではありません。
注:実際のコードでは、ルールを「レイヤー」で並べ替えてレイヤーを順番に計算するため、同時実行性について心配する必要はありません。各レイヤーは、前のレイヤーで計算された値にのみ依存します。どちらのモードもまったく同じレイヤー構造になっています。
結果
驚いたことに、解釈されたバージョンはコンパイルされたバージョンよりもはるかに高速に実行され、平均して4倍になります。つまり、コンパイルされたバージョンは約1,200のルールを実行するのに0.3秒かかりましたが、解釈されたバージョンは平均0.08〜0.1秒かかりました。
私のコンピューターはまあまあのデュアルコアCore2です。
.NET 4.0、VisualStudio10を使用しています。
パフォーマンスは、デバッグビルドとリリースビルドで同様です。
私の質問
コンパイルモードで大幅な速度低下を引き起こしている可能性があるのは何ですか?
注:1つの可能な回答を投稿しました