为什么在此测试中数组比字典快

时间:2019-04-05 09:04:31

标签: c# performance nunit

为什么在本次测试中数组比字典循环150次到大小为150的数组末尾的速度快于访问相同键的150次?

我虽然是由于优化,但已将其禁用

请解释

[MethodImplAttribute(MethodImplOptions.NoOptimization)]
    [Repeat(25)]
    [Test]
    public void DictionaryVSArray()
    {
        //array is faster from 0 up to 600 items;
        int collectionSize = 150;

        //populate array
        int[] array = new int[collectionSize];
        for (int i = 0; i < collectionSize; i++)
        {
            array[i] = i;
        }

        //populate dictionary
        Dictionary<int, int> dictionary = new Dictionary<int, int>();
        for (int i = 0; i < collectionSize; i++)
        {
            dictionary.Add(i, i);

        }

        //dictionary measurement
        Stopwatch dictStopWatch = new Stopwatch();
        dictStopWatch.Start();

        for(int i = 0; i< collectionSize; i++)
        {
            var s = dictionary[collectionSize-1];
        }
        dictStopWatch.Stop();
        TimeSpan elapsedDict = dictStopWatch.Elapsed;


        //array measurement
        Stopwatch arrayStopWatch = new Stopwatch();
        arrayStopWatch.Start();

        for (int i = 0; i < collectionSize; i++)
        {
            foreach (int item in array)
            {
                if (collectionSize-1 == item)
                {
                    break;
                }
            }
        }
        arrayStopWatch.Stop();
        TimeSpan elapsedArray = arrayStopWatch.Elapsed;

        Assert.Greater(elapsedArray, elapsedDict, $"array was faster by {(elapsedDict - elapsedArray).TotalMilliseconds} miliseconds");
    }

3 个答案:

答案 0 :(得分:4)

我认为您的测试完全有缺陷,我得到相反的结果。

对于我的设置

int collectionSize = 10000;

//populate array
_array = new int[collectionSize];

for (int i = 0; i < collectionSize; i++)
{
   _array[i] = i;
}

_dictionary = new Dictionary<int, int>();
for (int i = 0; i < collectionSize; i++)
{
   _dictionary.Add(i, i);

}

代码

[Test("List", "", true)]
public object Test1(int[] input, int scale)
{
   for (int i = 0; i < input.Length; i++)
   {
      foreach (int item in _array)
      {
         if (collectionSize - 1 == item)
         {
            break;
         }
      }
   }

   return null;
}

[Test("Dictionary", "", false)]
public object Test2(int[] input, int scale)
{
   for (int i = 0; i < input.Length; i++)
   {
      var s = _dictionary[input[i]];
   }

   return null;
}

基准

我每次运行100次测试,垃圾收集在每次运行之前进行一次热身运行,并生成0-255之间的1000个随机数进行测试(在发布模式下)。

┌──────────────────┬────────────────────────────────────────────┐
│        Test Mode │ Release (64Bit)                            │
│   Test Framework │ .NET Framework 4.7.1 (CLR 4.0.30319.42000) │
╞══════════════════╪════════════════════════════════════════════╡
│ Operating System │ Microsoft Windows 10 Pro                   │
│          Version │ 10.0.17134                                 │
├──────────────────┼────────────────────────────────────────────┤
│       CPU System │ Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz    │
│  CPU Description │ Intel64 Family 6 Model 42 Stepping 7       │
├──────────────────┼──────────┬──────────────────┬──────────────┤
│  Cores (Threads) │ 4 (8)    │     Architecture │ x64          │
│      Clock Speed │ 3401 MHz │        Bus Speed │ 100 MHz      │
│          L2Cache │ 1 MB     │          L3Cache │ 8 MB         │
└──────────────────┴──────────┴──────────────────┴──────────────┘

结果

┌── Standard input ────────────────────────────────────────────────────────┐
│ Value      │   Average │   Fastest │   Cycles │ Garbage │ Test │    Gain │
├── Scale 1,000 ────────────────────────────────────────────── 0.784 sec ──┤
│ Dictionary │ 13.680 µs │ 13.208 µs │ 50.621 K │ 0.000 B │ N/A  │ 99.76 % │
│ List       │  5.706 ms │  5.485 ms │ 19.406 M │ 0.000 B │ Base │  0.00 % │
└──────────────────────────────────────────────────────────────────────────┘

答案 1 :(得分:1)

字典有一个用于键的hastable,可以快速访问它。通过散列查找内容通常比比较内容更快。但是在您的情况下,可以快速比较整数值,并且因为您只有150 * 150个元素(22500个),所以几乎不需要时间,无论是字典还是数组。

尝试约1000 * 1000的东西。

您实际测量多少毫秒?

另外,您可能应该“搜索”循环的i值,而不总是使用相同的“ collectionSize”。也许编译器也在那里进行优化。

答案 2 :(得分:0)

在秒表中,您有一个if条件,可能在每次foreach重复开始时发生。