代码之家  ›  专栏  ›  技术社区  ›  Shalom Craimer

为什么UInt16数组的添加速度似乎比int数组快?

  •  7
  • Shalom Craimer  · 技术社区  · 16 年前

    UInt16[] 比添加两个数组 int[] 需要更少的CPU工作,不是吗?

    我运行了下面的测试代码,得到了以下结果:

    Int    for 1000 took 9896625613 tick (4227 msec)
    UInt16 for 1000 took 6297688551 tick (2689 msec)
    

    1. 创建两个名为 a b ,一次。
    2. 启动秒表。
    3. 添加 A. B ,逐项。这样做1000次。
    4. 停止秒表。
    5. 报告花了多长时间。

    int[] a, b 以及 UInt16 a,b . 以及 当我运行代码时 UInt16 int 数组。你能给我解释一下吗?

    以下是代码,如果您想自己尝试:

    public static UInt16[] GenerateRandomDataUInt16(int length)
    {
        UInt16[] noise = new UInt16[length];
        Random random = new Random((int)DateTime.Now.Ticks);
        for (int i = 0; i < length; ++i)
        {
            noise[i] = (UInt16)random.Next();
        }
    
        return noise;
    }
    
    public static int[] GenerateRandomDataInt(int length)
    {
        int[] noise = new int[length];
        Random random = new Random((int)DateTime.Now.Ticks);
        for (int i = 0; i < length; ++i)
        {
            noise[i] = (int)random.Next();
        }
    
        return noise;
    }
    
    public static int[] AddInt(int[] a, int[] b)
    {
        int len = a.Length;
        int[] result = new int[len];
        for (int i = 0; i < len; ++i)
        {
            result[i] = (int)(a[i] + b[i]);
        }
        return result;
    }
    
    public static UInt16[] AddUInt16(UInt16[] a, UInt16[] b)
    {
        int len = a.Length;
        UInt16[] result = new UInt16[len];
        for (int i = 0; i < len; ++i)
        {
            result[i] = (ushort)(a[i] + b[i]);
        }
        return result;
    }
    
    
    public static void Main()
    {
        int count = 1000;
        int len = 128 * 6000;
    
        int[] aInt = GenerateRandomDataInt(len);
        int[] bInt = GenerateRandomDataInt(len);
    
        Stopwatch s = new Stopwatch();
        s.Start();
        for (int i=0; i<count; ++i) 
        {
            int[] resultInt = AddInt(aInt, bInt);
        }
        s.Stop();
        Console.WriteLine("Int    for " + count 
                    + " took " + s.ElapsedTicks + " tick (" 
                    + s.ElapsedMilliseconds + " msec)");
    
        UInt16[] aUInt16 = GenerateRandomDataUInt16(len);
        UInt16[] bUInt16 = GenerateRandomDataUInt16(len);
    
        s = new Stopwatch();
        s.Start();
        for (int i=0; i<count; ++i) 
        {
            UInt16[] resultUInt16 = AddUInt16(aUInt16, bUInt16);
        }
        s.Stop();
        Console.WriteLine("UInt16 for " + count 
                    + " took " + s.ElapsedTicks + " tick (" 
                    + s.ElapsedMilliseconds + " msec)");
    
    
    }
    
    5 回复  |  直到 16 年前
        1
  •  6
  •   Pasi Savolainen    16 年前

    这意味着int16数组占用的内存面积占int32的一半。因此,更多的区域可以放入处理器缓存中,因此可以非常快速地访问。

    您可以在具有更多缓存的处理器上尝试该代码,并且差异可能更小。

    也可以尝试使用更大的阵列。

        2
  •  2
  •   Dipstick    16 年前

    数组是按字对齐的,但是没有理由让数组中的条目按字对齐。

        3
  •  1
  •   puffpio    16 年前

    几个因素

    2) 这将是有趣的,看看什么IL是产生的。由于您的代码非常简单(迭代和加法),编译器可能会对此进行优化,可能会在更大的寄存器中填充多个uint16,并对每条指令执行多个加法

        4
  •  1
  •   Michael Burr    16 年前

    只是一个小问题:UInt16数组的内存使用量较小,改善了内存特性(GC、缓存,谁知道还有什么)。由于分配似乎不太多,我猜缓存是主要因素。

    另外,您应该注意基准测试可能是一项棘手的工作—看起来您的时间可能包括一些JIT编译,这可能会扭曲结果。你可以试着颠倒测试的顺序 int UInt16 排列并查看计时是否跟随。

    jonskeet有(或有)一个简单的基准框架,他在考虑这些影响时编写了这个框架。我不知道它是否仍然可用(甚至适用);也许他会评论。

        5
  •  1
  •   Grzegorz Gierlik    16 年前

    两件事 :

    1. 经过 更大的阵列 int )比N的数组花费更多的时间 ushort
    2. 添加 变量可以通过添加两个 内景 内景 -- 没有 溢出 处理 例外 耗时