值类型化结构是基于堆栈的变量,驻留在处理器缓存而不是RAM中。所以通过使用值类型变量避免通过系统总线从处理器到RAM的跳转应该比使用参考类型变量更快。因此,而不是做stackallock
(Practical use of `stackalloc` keyword)我创建了一个如下结构表示基于堆栈的数组:为什么在我的情况下值类型变量比引用类型慢?
[StructLayout(LayoutKind.Sequential)]
public struct ArrayOf16Bytes
{
public Byte e0;
public Byte e1;
public Byte e2;
public Byte e3;
public Byte e4;
public Byte e5;
public Byte e6;
public Byte e7;
public Byte e8;
public Byte e9;
public Byte eA;
public Byte eB;
public Byte eC;
public Byte eD;
public Byte eE;
public Byte eF;
public byte this[Int32 index] {
get {
switch (index) {
case 0x0:
return e0;
case 0x1:
return e1;
case 0x2:
return e2;
case 0x3:
return e3;
case 0x4:
return e4;
case 0x5:
return e5;
case 0x6:
return e6;
case 0x7:
return e7;
case 0x8:
return e8;
case 0x9:
return e9;
case 0xA:
return eA;
case 0xB:
return eB;
case 0xC:
return eC;
case 0xD:
return eD;
case 0xE:
return eE;
case 0xF:
return eF;
default:
throw new IndexOutOfRangeException();
}
}
set {
switch (index) {
case 0x0:
e0 = value;
break;
case 0x1:
e1 = value;
break;
case 0x2:
e2 = value;
break;
case 0x3:
e3 = value;
break;
case 0x4:
e4 = value;
break;
case 0x5:
e5 = value;
break;
case 0x6:
e6 = value;
break;
case 0x7:
e7 = value;
break;
case 0x8:
e8 = value;
break;
case 0x9:
e9 = value;
break;
case 0xA:
eA = value;
break;
case 0xB:
eB = value;
break;
case 0xC:
eC = value;
break;
case 0xD:
eD = value;
break;
case 0xE:
eE = value;
break;
case 0xF:
eF = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
}
}
case
应该被编译为jump table
,因为cmp
和jump
是单周期指令(Is there any significant difference between using if/else and switch-case in C#?)的代码的第一块应比第二
比在下面的例子中的实际工作的阵列慢快得多:
[Test]
public void TestStackArrayPerformance() {
var random = new Xor128();
byte[] x = new byte[16];
ArrayOf16Bytes p = new ArrayOf16Bytes();
for (int i = 0; i < 16; i++) {
x [i] = p [i] = random.As<IUniform<byte>>().Evaluate();
}
var index = random.As<IUniform<Int32>>().Evaluate (0, 15);
var timer = DateTime.Now;
for (int i = 0; i < 1000000000; i++) {
var t = x [i & 0xF];
x [i & 0xF] = x [index];
x [index] = t;
}
Console.WriteLine ("Spinup took: {0}", DateTime.Now - timer);
timer = DateTime.Now;
for (int i = 0; i < 1000000000; i++) {
var t = x [i & 0xF];
x [i & 0xF] = x [index];
x [index] = t;
}
Console.WriteLine ("Operation 1 took: {0}", DateTime.Now - timer);
timer = DateTime.Now;
for (int i = 0; i < 100000000; i++) {
var t = p [i & 0xF];
p [i & 0xF] = p [index];
p [index] = t;
}
Console.WriteLine ("Operation 2 took: {0}", DateTime.Now - timer);
}
在我的机器这段代码显示出下列结果:
Spinup took: 00:00:00.3005500
Operation 1 took: 00:00:00.2959800
Operation 2 took: 00:00:04.4344340
我正在长时间工作在我自己开发的项目上,它的状态非常优化。我有一个想法,如何进一步推动它没有奏效。至于方法调用,你可能是对的,我认为编译器会内联代码,我打算用[MethodImpl(MethodImplOptions.AggressiveInlining)]覆盖]但索引器不能被覆盖,我懒得检查它方法,因为我甚至没有看到它会起作用的一个标志,即使'stackallock''数组比我的情况下的普通字节数组要慢,所以无论哪种方式都是一条小鱼来煎炸......谢谢无论如何... – Lu4