01: ///
02: /// 使用字节数组中的值初始 zipinteger 结构的新实例
03: /// 注意:本构造函数会破坏传入的 bits 参数的值。
04: ///
05: /// 顺序为 big-endian 的字节值的数组
06: public zipinteger(byte[] bits)
07: {
08: if (bits == null) throw new argumentnullexception("bits");
09: if (bits.length < 1 || bits.length > 9) throw new argumentexception("invalid length", "bits");
10: byte[] mask = { 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00 };
11: if (bits.length > 1 && bits.length < 9) bits[0] &= mask[bits.length - 1];
12: array.reverse(bits);
13: array.resize(ref bits, 8);
14: if (!bitconverter.islittleendian) array.reverse(bits);
15: data = decode(bitconverter.toint64(bits, 0));
16: }
mask 数组其实只需要初始化一次就行了,而不需要每次调用该构造函数时都进行初始化。也就是说,应该将 mask 变量声明为 static 的,如下所示:
static readonly byte[] mask = { 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00 };
愿望是美好的,现实是残酷的,加上 static 关键字后,再编译时 c# 编译器会报告以下错误:
error cs0106: 修饰符“static”对该项无效
也就是说,c# 语言不允许使用 static 修饰符来声明方法内部的变量。但是在 c/c++ 语言中是允许这么做的。
如果把该构造函数内部的 mask 变量提升到构造函数外部,成为 zipinteger 结构的字段成员,就可以声明为 static 的。但是这样一样,读这段代码的人就不容易弄清楚 mask 字段只在这个构造函数内部使用,成为代码的“坏味道”,一点也不优雅了。
好了,让我们写一小段程序来测试一下加上 static 后对运行效率的影响:
01: using system;
02: using system.io;
03: using system.diagnostics;
04: using skyiv.numerics;
05:
06: namespace skyiv.tester
07: {
08: sealed class statictester
09: {
10: static void main()
11: {
12: try
13: {
14: new statictester().run(100000000);
15: }
16: catch (exception ex)
17: {
18: console.writeline(ex);
19: }
20: }
21:
22: void run(int count)
23: {
24: console.writeline(" os version: " + environment.osversion);
25: console.writeline(" clr version: " + environment.version);
26: using (var reader = new memorystream(getbytes(count)))
27: {
28: var watch = stopwatch.startnew();
29: var n = 0;
30: for (var i = 0; i < 10; i++)
31: {
32: reader.seek(0, seekorigin.begin);
33: while (zipinteger.read(reader).hasvalue) n++;
34: }
35: watch.stop();
36: console.writeline(" count: " + n.tostring("n0"));
37: console.writeline("milliseconds: " + watch.elaps教程edmilliseconds.tostring("n0"));
38: }
39: }
40:
41: byte[] getbytes(int count)
42: {
43: var bits = new byte[count];
44: var rand = new random(123456);
45: rand.nextbytes(bits);
46: return bits;
47: }
48: }
49: }
上述程序中第 44 行使用固定的种子初始化 random 类的新实例,从而产生相同的随机数序列,以便用相同的测试用例来进行测试,使测试结果具有可比性。注意,在上述程序中如果 count 值和随机数的种子选取得不好,执行到第 33 行的 zipinteger.read 方法时是有可能抛出 endofstreamexception 异常的。
这个测试程序在 windows vista 操作系统的 .net framework 4 环境下的运行结果如下所示:
os version: microsoft windows nt 6.0.6002 service pack 2
clr version: 4.0.30319.1
count: 500,990,730
milliseconds: 181,886
将这个测试程序对 mask 变量是非静态的和静态的两种情况分别运行五次,得到的 milliseconds 值如下表所示:
序号 非静态 静态
1 181,886 167,528
2 179,074 166,847
3 180,309 166,526
4 183,542 166,399
5 179,469 167,365
平均 180,856 166,933
经过简单的计算得知,静态情况下比非静态情况下的平均运行效率提高了 7.7%,还是很可观的。
这个测试程序在 ubuntu 10.10 操作系统的 mono 2.6.7 环境的运行结果如下所示:
非静态 静态
os version: unix 2.6.35.24
clr version: 2.0.50727.1433
count: 500,992,030
milliseconds: 660,254
os version: unix 2.6.35.24
clr version: 2.0.50727.1433
count: 500,992,030
milliseconds: 583,387
经过简单的计算得知,静态情况下比非静态情况下的运行效率提高了 11.6%,更是有了较大的改进。
我们来看看这两种情况下 c# 编译器生成的 il 代码,在非静态的情况下的该实例构造函数(.ctor)的 il 代码:
001: .method public hidebysig specialname rtspecialname
002: instance void .ctor(uint8[] bits) cil managed
003: {
004: // 代码大小 181 (0xb5)
005: .maxstack 5
006: .locals init (uint8[] v_0,
007: bool v_1)
008: il_0000: nop
009: il_0001: ldarg.1
010: il_0002: ldnull
011: il_0003: ceq
012: il_0005: ldc.i4.0
013: il_0006: ceq
014: il_0008: stloc.1
015: il_0009: ldloc.1
016: il_000a: brtrue.s il_0017
017: il_000c: ldstr "bits"
018: il_0011: newobj instance void [mscorlib]system.argumentnullexception::.ctor(string)
019: il_0016: throw
020: il_0017: ldarg.1
021: il_0018: ldlen
022: il_0019: conv.i4
023: il_001a: ldc.i4.1
024: il_001b: blt.s il_0029
025: il_001d: ldarg.1
026: il_001e: ldlen
027: il_001f: conv.i4
028: il_0020: ldc.i4.s 9
029: il_0022: cgt
030: il_0024: ldc.i4.0
031: il_0025: ceq
032: il_0027: br.s il_002a
033: il_0029: ldc.i4.0
034: il_002a: stloc.1
035: il_002b: ldloc.1
036: il_002c: brtrue.s il_003e
037: il_002e: ldstr "invalid length"
038: il_0033: ldstr "bits"
039: il_0038: newobj instance void [mscorlib]system.argumentexception::.ctor(string,
040: string)
041: il_003d: throw
042: il_003e: ldc.i4.8
043: il_003f: newarr [mscorlib]system.byte
044: il_0044: dup
045: il_0045: ldtoken field int64 '
046: {78063cdc-e5ee-4c6b-a62d-fd0f919f6111}'::'$$method0x6000006-1'
047: il_004a: call void [mscorlib]system.runtime.compilerservices.runtimehelpers::
048: initializearray(class [mscorlib]system.array,
049: valuetype [mscorlib]system.runtimefieldhandle)
050: il_004f: stloc.0
051: il_0050: ldarg.1
052: il_0051: ldlen
053: il_0052: conv.i4
054: il_0053: ldc.i4.1
055: il_0054: ble.s il_0062
056: il_0056: ldarg.1
057: il_0057: ldlen
058: il_0058: conv.i4
059: il_0059: ldc.i4.s 9
060: il_005b: clt
061: il_005d: ldc.i4.0
062: il_005e: ceq
063: il_0060: br.s il_0063
064: il_0062: ldc.i4.1
065: il_0063: stloc.1
066: il_0064: ldloc.1
067: il_0065: brtrue.s il_0082
068: il_0067: ldarg.1
069: il_0068: ldc.i4.0
070: il_0069: ldelema [mscorlib]system.byte
071: il_006e: dup
072: il_006f: ldobj [mscorlib]system.byte
073: il_0074: ldloc.0
074: il_0075: ldarg.1
075: il_0076: ldlen
076: il_0077: conv.i4
077: il_0078: ldc.i4.1
078: il_0079: sub
079: il_007a: ldelem.u1
080: il_007b: and
081: il_007c: conv.u1
082: il_007d: stobj [mscorlib]system.byte
083: il_0082: ldarg.1
084: il_0083: call void [mscorlib]system.array::reverse(class [mscorlib]system.array)
085: il_0088: nop
086: il_0089: ldarga.s bits
087: il_008b: ldc.i4.8
088: il_008c: call void [mscorlib]system.array::resize
089: int32)
090: il_0091: nop
091: il_0092: ldsfld bool [mscorlib]system.bitconverter::islittleendian
092: il_0097: stloc.1
093: il_0098: ldloc.1
094: il_0099: brtrue.s il_00a2
095: il_009b: ldarg.1
096: il_009c: call void [mscorlib]system.array::reverse(class [mscorlib]system.array)
097: il_00a1: nop
098: il_00a2: ldarg.0
099: il_00a3: ldarg.1
100: il_00a4: ldc.i4.0
101: il_00a5: call int64 [mscorlib]system.bitconverter::toint64(uint8[],
102: int32)
103: il_00aa: call int64 skyiv.numerics.zipinteger::decode(int64)
104: il_00af: stfld int64 skyiv.numerics.zipinteger::data
105: il_00b4: ret
106: } // end of method zipinteger::.ctor
上述 il 代码的第 42 行到第 49 行对 mask 数组进行初始化,紧接着在第 50 行用“stloc.0”指令保存起来,然后在第 73 行用“ldloc.0”指令引用。
再看看静态的情况下该实例构造函数(.ctor)的 il 代码:
01: .method public hidebysig specialname rtspecialname
02: instance void .ctor(uint8[] bits) cil managed
03: {
04: // 代码大小 167 (0xa7)
05: .maxstack 5
06: .locals init (bool v_0)
07: il_0000: nop
08: il_0001: ldarg.1
09: il_0002: ldnull
10: il_0003: ceq
11: il_0005: ldc.i4.0
12: il_0006: ceq
13: il_0008: stloc.0
14: il_0009: ldloc.0
15: il_000a: brtrue.s il_0017
16: il_000c: ldstr "bits"
17: il_0011: newobj instance void [mscorlib]system.argumentnullexception::.ctor(string)
18: il_0016: throw
19: il_0017: ldarg.1
20: il_0018: ldlen
21: il_0019: conv.i4
22: il_001a: ldc.i4.1
23: il_001b: blt.s il_0029
24: il_001d: ldarg.1
25: il_001e: ldlen
26: il_001f: conv.i4
27: il_0020: ldc.i4.s 9
28: il_0022: cgt
29: il_0024: ldc.i4.0
30: il_0025: ceq
31: il_0027: br.s il_002a
32: il_0029: ldc.i4.0
33: il_002a: stloc.0
34: il_002b: ldloc.0
35: il_002c: brtrue.s il_003e
36: il_002e: ldstr "invalid length"
37: il_0033: ldstr "bits"
38: il_0038: newobj instance void [mscorlib]system.argumentexception::.ctor(string,
39: string)
40: il_003d: throw
41: il_003e: ldarg.1
42: il_003f: ldlen
43: il_0040: conv.i4
44: il_0041: ldc.i4.1
45: il_0042: ble.s il_0050
46: il_0044: ldarg.1
47: il_0045: ldlen
48: il_0046: conv.i4
49: il_0047: ldc.i4.s 9
50: il_0049: clt
51: il_004b: ldc.i4.0
52: il_004c: ceq
53: il_004e: br.s il_0051
54: il_0050: ldc.i4.1
55: il_0051: stloc.0
56: il_0052: ldloc.0
57: il_0053: brtrue.s il_0074
58: il_0055: ldarg.1
59: il_0056: ldc.i4.0
60: il_0057: ldelema [mscorlib]system.byte
61: il_005c: dup
62: il_005d: ldobj [mscorlib]system.byte
63: il_0062: ldsfld uint8[] skyiv.numerics.zipinteger::mask
64: il_0067: ldarg.1
65: il_0068: ldlen
66: il_0069: conv.i4
67: il_006a: ldc.i4.1
68: il_006b: sub
69: il_006c: ldelem.u1
70: il_006d: and
71: il_006e: conv.u1
72: il_006f: stobj [mscorlib]system.byte
73: il_0074: ldarg.1
74: il_0075: call void [mscorlib]system.array::reverse(class [mscorlib]system.array)
75: il_007a: nop
76: il_007b: ldarga.s bits
77: il_007d: ldc.i4.8
78: il_007e: call void [mscorlib]system.array::resize
79: int32)
80: il_0083: nop
81: il_0084: ldsfld bool [mscorlib]system.bitconverter::islittleendian
82: il_0089: stloc.0
83: il_008a: ldloc.0
84: il_008b: brtrue.s il_0094
85: il_008d: ldarg.1
86: il_008e: call void [mscorlib]system.array::reverse(class [mscorlib]system.array)
87: il_0093: nop
88: il_0094: ldarg.0
89: il_0095: ldarg.1
90: il_0096: ldc.i4.0
91: il_0097: call int64 [mscorlib]system.bitconverter::toint64(uint8[],
92: int32)
93: il_009c: call int64 skyiv.numerics.zipinteger::decode(int64)
94: il_00a1: stfld int64 skyiv.numerics.zipinteger::data
95: il_00a6: ret
96: } // end of method zipinteger::.ctor
上述 il 代码中就没有对 mask 数组进行初始化,而是在第 63 行用“ldsfld”指令直接引用 zipinteger 结构的静态字段,即已经初始化好了的 mask 数组。这个 mask 数组是在 zipinteger 结构的静态构造函数(.cctor)中初始化的,如下所示:
01: .method private hidebysig specialname rtspecialname static
02: void .cctor() cil managed
03: {
04: // 代码大小 61 (0x3d)
05: .maxstack 8
06: il_0000: ldc.i8 0x8000000000000000
07: il_0009: call valuetype skyiv.numerics.zipinteger skyiv.numerics.zipinteger::op_implicit(int64)
08: il_000e: stsfld valuetype skyiv.numerics.zipinteger skyiv.numerics.zipinteger::minvalue
09: il_0013: ldc.i8 0x7fffffffffffffff
10: il_001c: call valuetype skyiv.numerics.zipinteger skyiv.numerics.zipinteger::op_implicit(int64)
11: il_0021: stsfld valuetype skyiv.numerics.zipinteger skyiv.numerics.zipinteger::maxvalue
12: il_0026: ldc.i4.8
13: il_0027: newarr [mscorlib]system.byte
14: il_002c: dup
15: il_002d: ldtoken field int64 '
16: {cdcdeb38-994e-4730-8d14-55b1dbde4b1b}'::'$$method0x6000016-1'
17: il_0032: call void [mscorlib]system.runtime.compilerservices.runtimehelpers::
18: initializearray(class [mscorlib]system.array,
19: valuetype [mscorlib]system.runtimefieldhandle)
20: il_0037: stsfld uint8[] skyiv.numerics.zipinteger::mask
21: il_003c: ret
22: } // end of method zipinteger::.cctor
可以看出,在上述 il 代码中的第 12 到第 20 行对静态的 mask 数组进行了初始化。
相对应的非静态情况下的 zipinteger 结构的静态构造函数(.cctor)就没有对 mask 数组进行初始化的语句:
01: .method private hidebysig specialname rtspecialname static
02: void .cctor() cil managed
03: {
04: // 代码大小 39 (0x27)
05: .maxstack 8
06: il_0000: ldc.i8 0x8000000000000000
07: il_0009: call valuetype skyiv.numerics.zipinteger skyiv.numerics.zipinteger::op_implicit(int64)
08: il_000e: stsfld valuetype skyiv.numerics.zipinteger skyiv.numerics.zipinteger::minvalue
09: il_0013: ldc.i8 0x7fffffffffffffff
10: il_001c: call valuetype skyiv.numerics.zipinteger skyiv.numerics.zipinteger::op_implicit(int64)
11: il_0021: stsfld valuetype skyiv.numerics.zipinteger skyiv.numerics.zipinteger::maxvalue
12: il_0026: ret
13: } // end of method zipinteger::.cctor