vb.net – AndAlso OrElse可能会异常缓慢

前端之家收集整理的这篇文章主要介绍了vb.net – AndAlso OrElse可能会异常缓慢前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用VB.NET 2010编写一个计算密集型程序,我希望优化速度.我发现如果将操作结果分配给类级别的变量,则运算符AndAlso和OrElse异常慢.例如,虽然语句
a = _b AndAlso _c  
_a = a

在它们之间的编译exe中,大约有6个机器周期,单个语句

_a = _b AndAlso _c

大约需要80个机器周期.这里_a,_b和_c是Form1的私有布尔变量,所讨论的语句是Form1的实例过程,其中a是局部布尔变量.

我找不到为什么单一的陈述需要这么久.我已经使用NetReflector探索它到CIL代码的水平,这看起来不错:

Instruction               Explanation                              Stack  
00: ldarg.0               Push Me (ref to current inst of Form1)   Me  
01: ldarg.0               Push Me                                  Me,Me  
02: ldfld bool Form1::_b  Pop Me,read _b and push it              _b,Me  
07: brfalse.s 11          Pop _b; if false,branch to 11           Me  
09: ldarg.0               (_b true) Push Me                        Me,Me  
0a: ldfld bool Form1::_c  (_b true) Pop Me,read _c and push it    _c,Me  
0f: brtrue.s 14           (_b true) Pop _c; if true,branch to 14  Me  
11: ldc.i4.0              (_b,_c not both true) Push result 0     result,Me  
12: br.s 15               Jump unconditionally to 15               result,Me  
-----  
14: ldc.i4.1              (_b,_c both true) Push result 1         result,Me  
15: stfld bool Form1::_a  Pop result and Me; write result to _a    (empty)  
1a:

任何人都可以说明为什么这个语句_a = _b AndAlso _c需要80个机器周期,而不是预测的5个左右?

我使用Windows XP与.NET 4.0和Visual Studio Express 2010.我用一个坦白的脏片段测量了我自己的时间,它基本上使用一个Stopwatch对象来对一个For-Next循环进行1000次迭代,包含有关代码,将其与空For-Next循环进行比较;它在两个循环中都包含一个无用的指令,以浪费几个周期并防止处理器停滞.粗鲁但足够我的目的.

这里有两个因素使得这个代码变慢.您不能从IL看到这一点,只有机器代码可以给你洞察力.

首先是与AndAlso运算符关联的一般.它是一个短路操作符,如果左侧操作数的计算结果为False,则右侧的操作数不会得到评估.这需要机器代码中的分支.分支是处理器可以做的最慢的事情之一,它必须在分支机构前面猜测,以避免冲洗管道的风险.如果它猜测错了,那将会是一个重大的打击.非常好的覆盖在this post.如果一个变量是高度随机的,并且分支因此预测不足,典型的perf损失约为500%.

您可以通过使用And运算符来避免这种风险,而不需要机器代码中的分支.它只是一个指令,AND由处理器实现.在这样一个表达式中,没有任何意义上的赞同,如果右手操作数得到评估,没有任何问题.这里不适用,但即使IL显示分支,则抖动仍可能使CMOV指令(条件移动)使机器代码无分支.

但在你的情况下最重要的是Form类继承自MarshalByRefObject类.继承链是MarshalByRefObject>成分>控制> ScrollableControl> ContainerControl>形成.

MBRO由Just-in-Time编译器特别处理,代码可能正在使用类对象的代理,而真实对象生活在另一个AppDomain或另一台机器中.代理对于几乎任何类型的成员的抖动都是透明的,它们被实现为简单的方法调用.除了字段,它们不能被代理,因为对存储器读/写而不是方法调用进行了一个字段的访问.如果抖动不能证明该对象是本地的,则使用JIT_GetFieldXxx()和JIT_SetFieldXxx()的帮助方法强制调用该CLR. CLR知道对象引用是代理还是真正的交易,并处理差异.开销是相当大的,关于正确的80个循环.

只要变量是Form类的成员,就没有太多的可以做到这一点.将它们转换为辅助类是解决方法.

猜你在找的VB相关文章