-
20-09-2019 - |
题
我知道如何通过动态代码生成来提高性能,但我不确定哪种方法是解决这个问题的最佳方法。
假设我有一堂课
class Calculator
{
int Value1;
int Value2;
//..........
int ValueN;
void DoCalc()
{
if (Value1 > 0)
{
DoValue1RelatedStuff();
}
if (Value2 > 0)
{
DoValue2RelatedStuff();
}
//....
//....
//....
if (ValueN > 0)
{
DoValueNRelatedStuff();
}
}
}
DoCalc方法处于最底层,在计算过程中会被多次调用。另一个重要的方面是ValueN仅在开始时设置并且在计算过程中不会改变。DoCalc 方法中的许多 if 是不必要的,因为 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 的值创建这样的方法,并在计算过程中使用生成的方法。
我想我可以使用表达式树来实现这一点,但是表达式树只能与简单的 lambda 函数一起使用,所以我不能使用 if、while 等。函数体内。所以在这种情况下我需要以适当的方式改变这个方法。
另一种可能性是将必要的代码创建为字符串并动态编译它。但如果我能采用现有的方法并进行相应的修改,那对我来说会更好。
还有 Reflection.Emit,但我不想坚持使用它,因为它很难维护。
顺便提一句。我并不局限于 C#。因此,我愿意接受最适合此类问题的编程语言的建议。由于一些原因,LISP 除外。
一项重要的澄清。DoValue1RelatedStuff() 不是我的算法中的方法调用。这只是一些基于公式的计算,而且速度相当快。我应该这样写
if (Value1 > 0)
{
// Do Value1 Related Stuff
}
我已经运行了一些性能测试,我可以看到,使用两个 if,当其中一个被禁用时,优化方法比使用冗余 if 快大约 2 倍。
这是我用于测试的代码:
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;
}
}
解决方案
我通常会别想这样的优化。多少工作没有DoValueXRelatedStuff()
吗?超过10至50个处理器周期?是?这意味着你要建立一个相当复杂的系统,节省10%以下的执行时间(这似乎相当乐观对我来说)。这可以很容易下降到小于1%。
有没有空间其他优化?更好的算法?一个你真的需要消除单一分行采取只有一个处理器周期(如果分支预测是正确的)?是?你是不是应该想想汇编或具体的,而不是使用.NET别的更多的机器编写代码?
你能给N
的顺序,所述的典型方法的复杂性,和表达式通常评估为真?的比率
其他提示
如果你是真正进入代码优化 - 你做任何事情之前 - 运行探查!它会告诉你在哪里的瓶颈和哪些领域值得优化。
此外 - 如果语言的选择并不限于(除了LISP)则事击败汇编在性能方面)
记得通过使用汇编重写一些内部函数(像您有一个)实现某些性能的魔法。
在你做任何事情之前, 你真的有问题吗?
IE。它运行的时间是否足以打扰您?
如果是这样,找出实际上需要时间的事情, 不是你猜的那样. 这 这是我用来查看时间去向的快速、肮脏且高效的方法。
现在,您正在谈论解释与编译。解释后的代码通常比编译后的代码慢 1-2 个数量级。原因是口译员不断地弄清楚下一步该做什么, 然后忘记, ,编译代码时 只知道.
如果您处于这种情况,那么付出翻译的代价以获得编译代码的速度可能是有意义的。