使用foreach循环遍历字典是否需要正常的散列表访问?

时间:2012-05-17 22:22:33

标签: c# .net performance dictionary

我正在编写一个主要是性能密集型的应用程序。在今天编写快速基准之后,我发现字典访问时间明显慢于数组访问时间(最多100次),尽管两者都是O(1)。我尝试在互联网上找到类似的结果,但无济于事。这看起来是对的吗?这对我来说很有意义,因为字典中有哈希,而不是数组。

我现在正在权衡字典的优缺点,并考虑是否应该尝试更快的实现。在我的应用程序的至少3个实例中,我使用foreach循环遍历我的所有词典(有很多)。所以现在要回答我的问题,foreach循环是否必须经历“慢”(我在这里相对而言)散列过程,或者它是否只是维护一个可以快速迭代的内部列表?如果是这种情况,我更有可能坚持使用字典。

对于一些额外信息,应用程序是一个简单的2D游戏,字典将存储在游戏实体中。虽然确实有很多。是的,我已经有了一个有效的解决方案。这是后优化,而不是预先。

这是我写的基准。这可能是非常错误的,因为我不是该领域的专家:

        public static int dict(Dictionary<key,int> dict, key k)
        {
            int i;
            //dict.TryGetValue(k,out i);
            i = dict[k];  //both these version yield the same results

            return i;
        }

        public static int arr(int[,] arr, key k)
        {
            int i;
            i = arr[k.x, k.y];

            return i;
        }

        public struct key
        {
            public int x, y;

            public key (int x, int y){
                this.x = x;
                this.y = y;
            }
        }

        public static void Main()
        {
            int dim = 256;
            Dictionary<key,int> dictVar = new Dictionary<key,int>(dim*dim*10);

            int[,] arrVar = new int[dim,dim];

            for (int i = 0; i < dim; ++i)
            {
                for (int j = 0; j < dim; ++j)
                {
                    arrVar[i, j] = i + j * i;
                    dictVar.Add(new key(i, j), i + i * j);
                }  
            }

            const int iterations = 1000000;
            key k = new key(200, 200);
            TestTime(dict, dictVar, k, iterations);
            TestTime(arr, arrVar, k, iterations);
        }

        public static void TestTime<T1, T2, TR>(Func<T1, T2, TR> action, T1 obj1,
                                                T2 obj2, int iterations)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            for (int i = 0; i < iterations; ++i)
                action(obj1, obj2);
            Console.WriteLine(action.Method.Name + " took " + stopwatch.Elapsed);
        }

1 个答案:

答案 0 :(得分:1)

它维护一个循环的内部列表,但列表的类型为Entry<TKey, TValue>[],因此每次都必须构造一个KeyValuePair。我猜这是造成经济放缓的原因。