.NET下几种动态生成代码方式比较

场景:

        平时在日常工作中往往会遇到这样的情况:一般的解决方案性能不是最好的,但性能最好的解决方案往往又不一定容易理解。如何兼顾这两者呢?这里有一个Microsoft网站上的例子,它用了几种动态代码生成的方法去实现同一个问题,可以对它们的性能做一个简单的比较,以后到底用那种方法心中就有数了。


要解决的问题:

计算一个多项式的值:
        Y = A0 + A1 * X + A2 * X2 + … + An * Xn



比较指标:

1. 参数只有一个的情况: A 0=5.5
2. 参数只有7个的情况: A 0=5.5  A 1=7.0  A 2=15 A 3=30 A 4=500 A 5=100 A 6=1
3. 参数有30个的情况:A 0=0 A 1=1 ... A 29=29
4. 参数有50个的情况:A 0=0 A 1=1 ... A 49=49
5. 参数有100个的情况:A 0=0 A 1=1 ... A 99=99

实现方式:

       最普通的用循环的实现方式:(不涉及动态编程的内容,参考作用)
       对参数进行循环。

None.gif      public   override   double  Evaluate( double  value)
ExpandedBlockStart.gif    
{
InBlock.gif        
double retval = coefficients[0];
InBlock.gif
InBlock.gif        
double f = value;
InBlock.gif
InBlock.gif        
for (int i = 1; i < coefficients.Length; i++)
ExpandedSubBlockStart.gif        
{
InBlock.gif            retval 
+= coefficients[i] * f;
InBlock.gif            f 
*= value;
InBlock.gif    
ExpandedSubBlockEnd.gif        }

InBlock.gif        
return(retval);
ExpandedBlockEnd.gif    }

None.gif

       显然这样的方式循环是很多的,这里对参数循环,外面还要对指数幂循环。为了减少循环的次数,考虑将上面Evaluate的方法用动态代码的方式实现。
poly1.JPG

有以下几种动态代码的实现方式:
1. <<PolyCodeSlow.cs>>
步骤:
a.用文件方式动态编写一个类来实现Evaluate方法;
b.动态编译生成DLL;
c.通过反射的方式来调用结果;

动态生成类的文件如下:(参数为7的情况)

None.gif //  polynomial evaluator
None.gif
//  Evaluating y = 5.5 + 7 X^1 + 7 X^2 + 7 X^3 + 7 X^4 + 7 X^5 + 7 X^6
None.gif

None.gif
class  Poly_1
ExpandedBlockStart.gif
{
InBlock.gif
public double Evaluate(double value)
ExpandedSubBlockStart.gif
{
InBlock.gif    
return(
InBlock.gif        
5.5
InBlock.gif        
+ value * (7 
InBlock.gif        
+ value * (15 
InBlock.gif        
+ value * (30 
InBlock.gif        
+ value * (500 
InBlock.gif        
+ value * (100 
InBlock.gif        
+ value * (1 
InBlock.gif    )))))));
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}


2.<<PolyCode.cs>>
基本思路和上面一样,但稍有不同的是动态编写的类实现了接口。
a.用文件方式动态编写一个类来实现Evaluate方法,并且实现接口;
b.动态编译生成DLL;
c.通过接口来调用结果;

None.gif //  polynomial evaluator
None.gif
//  Evaluating y = 5.5 + 7 X^1 + 15 X^2 + 30 X^3 + 500 X^4 + 100 X^5 + 1 X^6
None.gif

None.gif
class  Poly_1001: PolyInterface.IPolynomial
ExpandedBlockStart.gif
{
InBlock.gif
public double Evaluate(double value)
ExpandedSubBlockStart.gif
{
InBlock.gif    
return(
InBlock.gif        
5.5
InBlock.gif        
+ value * (7 
InBlock.gif        
+ value * (15 
InBlock.gif        
+ value * (30 
InBlock.gif        
+ value * (500 
InBlock.gif        
+ value * (100 
InBlock.gif        
+ value * (1 
InBlock.gif    )))))));
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}


3.<<PolyCodeDom.cs>>
基本思路和2相同,但动态生成类的方法不同。
a.用CodeDom来动态编写一个类来实现Evaluate方法,并且实现接口;
b.动态编译生成DLL;
c.通过接口来调用结果;

None.gif //  Polynomial evaluator
None.gif
//  Evaluating Y = 5.5 + 7 X^1 + 15 X^2 + 30 X^3 + 500 X^4 + 100 X^5 + 1 X^6
ExpandedBlockStart.gif
public   class  Poly_1001 : PolyInterface.IPolynomial  {
InBlock.gif    
ExpandedSubBlockStart.gif    
public double Evaluate(System.Double x) {
InBlock.gif        
return (5.5 
InBlock.gif                    
+ (x 
InBlock.gif                    
* (7 
InBlock.gif                    
+ (x 
InBlock.gif                    
* (15 
InBlock.gif                    
+ (x 
InBlock.gif                    
* (30 
InBlock.gif                    
+ (x 
InBlock.gif                    
* (500 
InBlock.gif                    
+ (x 
InBlock.gif                    
* (100 
InBlock.gif                    
+ (x 
InBlock.gif                    
* (1 + 0)))))))))))));
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}


4.<<PolyEmit.cs>>
这里直接用元编程技术,跳过文本编译生成的过程,直接生成动态编译结果然后调用。
a.建立动态程序集;
b.元编程技术实现动态类和方法;
c.通过动态类的接口调用结果;



结果比较: (数据是在机子上某次运行的结果)

动态代码花费的时间(主要花费在代码编译上)

花费时间(s)1个参数7个参数30个参数50个参数100个参数
一般代码方式(PolySimple.cs)00000
动态代码方式一(PolyCodeSlow.cs)0.490.370.340.340.36
动态代码方式二(PolyCode.cs)0.470.40.360.370.43
动态代码方式三(PolyCodeDom.cs)0.510.380.430.390.38
动态代码方式四(PolyEmit.cs)0.010000

每秒可以运行多少个表达式(性能比较)
 1个参数7个参数30个参数50个参数100个参数
一般代码方式(PolySimple.cs)2484414910976159360626721071761050327
动态代码方式一(PolyCodeSlow.cs)5990559525589815786056057
动态代码方式二(PolyCode.cs)802588571170321429739091930444980942
动态代码方式三(PolyCodeDom.cs)1136363491100179829600871917754769594
动态代码方式四(PolyEmit.cs)1136363491191672229359061925118859074


由此可见:

        后面三种动态方式的性能差不多,虽然元编程不花费时间在编译上,但其技术难度相对也高些。

相关例子下载
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值