У меня есть движок правил, который поддерживает два режима работы:
- Компиляция в программу на 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
Здесь «Выражение» является частью сторонней библиотеки, которая анализирует простую строку в простой набор инструкций обратного полирования стека, которые затем можно интерпретировать. Это не объект дерева выражений в LINQ - просто для пояснения.
Примечание: не беспокойтесь о параллелизме, поскольку в реальном коде я сортирую правила по «слоям» и последовательно вычисляю слои, каждый из которых зависит только от значений, рассчитанных в предыдущих слоях. Оба режима имеют одинаковую структуру слоев.
Результаты
Шокирующе, интерпретированная версия работает НАМНОГО быстрее, чем скомпилированная версия, в среднем в 4 раза! Другими словами, скомпилированной версии потребовалось 0,3 с, чтобы пройти около 1200 правил, в то время как интерпретированной версии потребовалось в среднем 0,08-0,1 с.
Мой компьютер - так себе двухъядерный Core2.
Я использую .NET 4.0, Visual Studio 10.
Производительность аналогична в сборках Debug или Release.
Мой вопрос
Что может быть причиной значительного замедления в скомпилированном режиме?
ПРИМЕЧАНИЕ: я разместил один возможный ответ