【发布时间】:2015-05-13 18:37:54
【问题描述】:
我正在阅读《CLR via C#》(第 4 版)一书,不是作为 C# 的新手,而是作为一个了解该语言的人,试图提高我对 CLR 底层功能的掌握。
无论如何,在本书中给出了一个示例(pg127-131),该示例讨论了值类型的装箱/拆箱,该示例以对 Console.WriteLine 的调用结束,其中值类型连接到作为参数传递的字符串。
这本书解释了装箱和拆箱/复制操作会导致开销,我已经知道了,但随后说明可以通过在传入的值类型上运行 .ToString() 来优化示例。
我创建了一个示例程序并对其进行了编译,然后使用 ILDASM 检查它生成的 IL。带有 ToString 的版本本质上是相同的,但是用对 ToString 的“调用”替换了“box”指令(这并不令人震惊)。
我在 100000 次运行的循环中对代码进行了基准测试,没有任何区别(它会波动哪个更快)。我意识到在进行基准测试(缓存等)时还有其他因素会起作用,但是按照本书的解释,即使在幼稚的基准测试中,我也希望在避免“盒子”指令时看到显着的差异..
仅仅是调用一个函数不是更好吗? ToString 中是否正在进行装箱操作,使好处无效并且这本书是错误的?有人可以对此有所了解吗?
作为参考,以下是两个 ILDASM 读数:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 24 (0x18)
.maxstack 2
.locals init (int32 V_0)
IL_0000: ldc.i4.4
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: box [mscorlib]System.Int32
IL_0008: ldstr "."
IL_000d: call string [mscorlib]System.String::Concat(object,
object)
IL_0012: call void [mscorlib]System.Console::WriteLine(string)
IL_0017: ret
} // end of method Program::Main
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 25 (0x19)
.maxstack 2
.locals init (int32 V_0)
IL_0000: ldc.i4.4
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call instance string [mscorlib]System.Int32::ToString()
IL_0009: ldstr "."
IL_000e: call string [mscorlib]System.String::Concat(string,
string)
IL_0013: call void [mscorlib]System.Console::WriteLine(string)
IL_0018: ret
} // end of method Program::Main
【问题讨论】:
-
看反汇编窗口,看看x86汇编代码有什么区别。
标签: c# performance cil boxing ildasm