У меня есть представление о том, как улучшить производительность с помощью динамической генерации кода, но я не уверен, что это лучший способ решить эту проблему.
Предположим, у меня есть класс
class Calculator
{
int Value1;
int Value2;
//..........
int ValueN;
void DoCalc()
{
if (Value1 > 0)
{
DoValue1RelatedStuff();
}
if (Value2 > 0)
{
DoValue2RelatedStuff();
}
//....
//....
//....
if (ValueN > 0)
{
DoValueNRelatedStuff();
}
}
}
Метод DoCalc находится на самом низком уровне и вызывается много раз во время расчета. Другим важным аспектом является то, что ValueN устанавливаются только в начале и не изменяются во время расчета. Так что многие из if в методе DoCalc не нужны, так как многие из ValueN равны 0. Поэтому я надеялся, что динамическое генерирование кода может помочь повысить производительность.
Например, если я создаю метод
void DoCalc_Specific()
{
const Value1 = 0;
const Value2 = 0;
const ValueN = 1;
if (Value1 > 0)
{
DoValue1RelatedStuff();
}
if (Value2 > 0)
{
DoValue2RelatedStuff();
}
....
....
....
if (ValueN > 0)
{
DoValueNRelatedStuff();
}
}
и компилировать его с включенными оптимизациями. Компилятор C # достаточно умен, чтобы хранить только необходимые вещи. Поэтому я хотел бы создать такой метод во время выполнения на основе значений ValueN и использовать сгенерированный метод во время вычислений.
Полагаю, я мог бы использовать для этого деревья выражений, но деревья выражений работают только с простыми лямбда-функциями, поэтому я не могу использовать такие вещи, как if, while и т. Д. Внутри тела функции. Поэтому в этом случае мне нужно соответствующим образом изменить этот метод.
Другая возможность - создать необходимый код в виде строки и динамически скомпилировать его. Но для меня было бы намного лучше, если бы я мог воспользоваться существующим методом и соответствующим образом изменить его.
Существует также Reflection.Emit, но я не хочу придерживаться его, поскольку его будет очень сложно поддерживать.
КСТАТИ. Я не ограничен C #. Так что я открыт для предложений языков программирования, которые лучше всего подходят для такого рода проблем. За исключением LISP по нескольким причинам.
Одно важное уточнение. DoValue1RelatedStuff () не является вызовом метода в моем алгоритме. Это просто расчет на основе формул, и он довольно быстрый. Я должен был написать это так
if (Value1 > 0)
{
// Do Value1 Related Stuff
}
Я провел несколько тестов производительности и вижу, что с двумя if, если один отключен, оптимизированный метод примерно в 2 раза быстрее, чем с избыточным if.
Вот код, который я использовал для тестирования:
public class Program
{
static void Main(string[] args)
{
int x = 0, y = 2;
var if_st = DateTime.Now.Ticks;
for (var i = 0; i < 10000000; i++)
{
WithIf(x, y);
}
var if_et = DateTime.Now.Ticks - if_st;
Console.WriteLine(if_et.ToString());
var noif_st = DateTime.Now.Ticks;
for (var i = 0; i < 10000000; i++)
{
Without(x, y);
}
var noif_et = DateTime.Now.Ticks - noif_st;
Console.WriteLine(noif_et.ToString());
Console.ReadLine();
}
static double WithIf(int x, int y)
{
var result = 0.0;
for (var i = 0; i < 100; i++)
{
if (x > 0)
{
result += x * 0.01;
}
if (y > 0)
{
result += y * 0.01;
}
}
return result;
}
static double Without(int x, int y)
{
var result = 0.0;
for (var i = 0; i < 100; i++)
{
result += y * 0.01;
}
return result;
}
}