2013-08-31 24 views
-1

值类型化结构是基于堆栈的变量,驻留在处理器缓存而不是RAM中。所以通过使用值类型变量避免通过系统总线从处理器到RAM的跳转应该比使用参考类型变量更快。因此,而不是做stackallockPractical 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,因为cmpjump是单周期指令(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 

回答

0

我不是这方面的专家,但我相信你有一些错误的假设这里:

价值类型化结构是基于堆栈的变量,驻留在处理器缓存而不是RAM中。所以通过使用值类型变量避免通过系统总线从处理器到RAM的跳转应该比使用参考类型变量更快。

仅仅因为某些参考类型并不意味着CPU缓存将不会被使用。堆栈不是可以使用缓存的唯一内存区域。另外,CPU在预取缓存等方面非常聪明,所以你通常不必像这样微处理你的内存。另外,请记住,当你在你的循环中访问你的struct时,它不仅仅是getter和setter中的指令,你不必担心;您还可以在任何时候执行包括索引器的方法调用的开销。方法调用包括将参数推送到堆栈,跳转到方法指令,将返回值推入堆栈,执行返回跳转等。因此,这比设置一个简单的指令更加昂贵也就不足为奇了数组值。

+0

我正在长时间工作在我自己开发的项目上,它的状态非常优化。我有一个想法,如何进一步推动它没有奏效。至于方法调用,你可能是对的,我认为编译器会内联代码,我打算用[MethodImpl(MethodImplOptions.AggressiveInlining)]覆盖]但索引器不能被覆盖,我懒得检查它方法,因为我甚至没有看到它会起作用的一个标志,即使'stackallock''数组比我的情况下的普通字节数组要慢,所以无论哪种方式都是一条小鱼来煎炸......谢谢无论如何... – Lu4

相关问题