C# 动态编译以提高性能
我知道如何通过动态代码生成来提高性能,但我不确定哪种方法是解决此问题的最佳方法 假设我有一节课C# 动态编译以提高性能,c#,performance,code-generation,dynamic-compilation,C#,Performance,Code Generation,Dynamic Compilation,我知道如何通过动态代码生成来提高性能,但我不确定哪种方法是解决此问题的最佳方法 假设我有一节课 class Calculator { int Value1; int Value2; //.......... int ValueN; void DoCalc() { if (Value1 > 0) { DoValue1RelatedStuff(); } if (Value2 > 0) { DoVal
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方法中的许多ifs都是不必要的,因为ValueN的许多ifs都是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等。因此,在这种情况下,我需要以适当的方式更改此方法
另一种可能是将必要的代码创建为字符串并动态编译。但是如果我能采用现有的方法并相应地修改它,对我来说会更好
还有反射。发射,但我不想坚持使用它,因为它很难维护
顺便说一句,我并不局限于C。所以我愿意接受最适合这种问题的编程语言的建议。除了LISP之外,还有几个原因
一个重要的澄清。DoValue1RelatedStuff()不是我的算法中的方法调用。这只是一些基于公式的计算,速度非常快。我应该这样写的
if (Value1 > 0)
{
// Do Value1 Related Stuff
}
我已经运行了一些性能测试,我可以看到在禁用一个ifs时,使用两个ifs时,优化方法的速度大约是使用冗余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;
}
}
公共课程
{
静态void Main(字符串[]参数)
{
int x=0,y=2;
var if_st=DateTime.Now.Ticks;
对于(变量i=0;i<10000000;i++)
{
带if(x,y);
}
var if_et=DateTime.Now.Ticks-if_st;
Console.WriteLine(if_et.ToString());
var noif_st=DateTime.Now.Ticks;
对于(变量i=0;i<10000000;i++)
{
没有(x,y);
}
var noif_et=DateTime.Now.Ticks-noif_st;
Console.WriteLine(noif_et.ToString());
Console.ReadLine();
}
带IF的静态双精度(整数x,整数y)
{
var结果=0.0;
对于(变量i=0;i<100;i++)
{
如果(x>0)
{
结果+=x*0.01;
}
如果(y>0)
{
结果+=y*0.01;
}
}
返回结果;
}
不带(整数x,整数y)的静态双精度
{
var结果=0.0;
对于(变量i=0;i<100;i++)
{
结果+=y*0.01;
}
返回结果;
}
}
我会惊讶地发现,在这种情况下,评估if语句的开销值得动态发出代码
现代CPU对和的支持,使得代码小段中的分支开销接近于零
您是否尝试过对代码的两个手工编码版本进行基准测试,一个包含所有if语句,但大多数都提供零值,另一个删除所有相同的if分支?我通常不会考虑这样的优化。
DoValueXRelatedStuff()
要做多少工作?超过10到50个处理器周期?对这意味着您将要构建一个相当复杂的系统,以节省不到10%的执行时间(这在我看来是非常乐观的)。这很容易降到1%以下
没有其他优化的空间吗?更好的算法?如果分支预测是正确的,您真的需要消除只占用单个处理器周期的单个分支吗?对您不应该考虑用汇编程序或其他更特定于机器的东西来编写代码,而不是使用.NET吗
您能给出
N
的顺序、典型方法的复杂性以及通常计算为true的表达式的比率吗?如果您真的对代码优化感兴趣,请先运行探查器!它将告诉您瓶颈在哪里,哪些方面值得优化
另外-如果语言选择不受限制(LISP除外),那么就性能而言,没有什么能打败汇编程序;)
我记得通过使用汇编程序重写一些内部函数(如您拥有的函数)实现了一些性能魔法。在您做任何事情之前,您是否真的有问题
i、 它跑的时间够长吗
如果是这样的话,找出真正需要时间的是什么,而不是你的猜测。是我用来判断时间流逝的快速、肮脏和高效的方法
现在,你谈论的是口译还是编译。解释代码通常比编译代码慢1-2个数量级。原因是解释器不断地计算下一步要做什么,然后忘记,而编译的代码只是知道而已
如果您处于这种情况,那么为获得编译代码的速度而付出翻译的代价可能是有意义的。我同意,N必须是数百,如果不是数千,并且大多数情况在实践中需要省略,我已经有好几年没有在ASM/IL级别做太多工作了,但我相信当前的英特尔处理器将预先决定