Eri*_*ith 15 vb.net performance logical-operators
我正在用VB.NET 2010编写一个计算密集型程序,我希望优化速度.如果操作的结果被分配给类级变量,我发现运算符AndAlso并且OrElse异常缓慢.例如,虽然声明
a = _b AndAlso _c
_a = a
Run Code Online (Sandbox Code Playgroud)
在编译的exe中,它们之间需要大约6个机器周期,单个语句
_a = _b AndAlso _c
Run Code Online (Sandbox Code Playgroud)
大约需要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:
Run Code Online (Sandbox Code Playgroud)
任何人都可以阐明为什么声明_a = _b AndAlso _c需要80个机器周期而不是预测的5个左右?
我正在使用带有.NET 4.0和Visual Studio Express 2010的Windows XP.我使用我自己的一个简单的脏片段来测量时间,它基本上使用一个Stopwatch对象来定时For-Next循环,包含有关代码的1000次迭代将它与空For-Next循环进行比较; 它包括两个循环中的一个无用指令,浪费几个周期并防止处理器停止.原油但足够我的目的.
Han*_*ant 12
这里有两个因素使得代码变慢.您无法从IL中看到这一点,只有机器代码可以为您提供见解.
首先是与AndAlso运算符关联的一般.它是一个短路运算符,如果左侧操作数的计算结果为False,则不会对右侧操作数进行求值.这需要机器代码中的分支.分支是一个处理器可以做的,它必须在最慢的事情之一猜在分支前面,以避免冲洗管道的风险.如果它猜错了那么它将会受到重大打击.这篇文章很好地介绍了.如果a变量是高度随机的,并且分支因此预测不佳,则典型的性能损失约为500%.
您可以通过使用And运算符来避免此风险,它不需要机器代码中的分支.它只是一条指令,由处理器实现.没有必要在这样的表达式中使用AndAlso,如果右侧操作数得到评估,没有任何问题.这里不适用,但即使IL显示分支,抖动仍可能使机器代码无分支,并带有CMOV指令(条件移动).
但在您的情况下,最重要的是Form类继承自MarshalByRefObject类.继承链是MarshalByRefObject> Component> Control> ScrollableControl> ContainerControl> Form.
MBRO由Just-in-Time编译器专门处理,代码可能与类对象的代理一起使用,真实对象存在于另一个AppDomain或另一台机器中.对于几乎任何类的成员,代理对抖动都是透明的,它们是作为简单的方法调用实现的.除了字段之外,它们不能被代理,因为对字段的访问是通过内存读/写来完成的,而不是方法调用.如果抖动无法证明该对象是本地的,那么它将被强制使用名为JIT_GetFieldXxx()和JIT_SetFieldXxx()的辅助方法调用CLR.CLR知道对象引用是代理还是真实交易并处理差异.开销非常大,80个周期听起来很合适.
只要变量是Form类的成员,就没有什么可以做的.将它们转移到帮助程序类是解决方法.
| 归档时间: |
|
| 查看次数: |
354 次 |
| 最近记录: |