Hashset vs Array,是否可以进一步优化?

时间:2016-11-07 12:37:19

标签: c# optimization

我的代码在整个程序中都有如下代码。一个例子是寻路,我在其中创建动态环境的快照,并使用创建的地图作为aStar算法的基础。

由于代码的执行时间影响了我可以利用寻路的最大单位数量,我想尽可能优化这里。

(我相信)性能最佳解决方案是:

  static int runtest(bool[,] coll, int size, int globalSize)
    {
        int counter = 0;
        for (int x = -size; x < size; x++)
        {
            for (int y = -size; y < size; y++)
            {
                if (coll[x+ globalSize, y+ globalSize])
                {
                    counter++;

                    int tx = x;
                    int ty = y;
                }
            }
        }
        return counter;
    }

但是我对使用数组时浪费的内存量感到不满意,所以我目前正在使用这个解决方案:

static int runtest(HashSet<int> coll, int size)
    {
        int counter = 0;
        for (int x = -size; x < size; x++)
        {
            for (int y = -size; y < size; y++)
            {
                if (coll.Contains(calculateHash(x, y)))
                {
                    counter++;

                    int tx = x;
                    int ty = y;
                }
            }
        }
        return counter;
    }

 public static int calculateHash(float x1, float y1)
        {
            int x = (int)Math.Floor(x1);
            int y = (int)Math.Floor(y1);

            return calculateHash(x, y);
        }

      //[MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static int calculateHash(int x, int y) {
            return x + (y << 16);
        }
    }

Array的实现速度提高了大约5倍,这是我必须要使用的东西,还是可以以某种方式进一步优化哈希版本?

完整测试代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int size = 240;
            HashSet<Vector2> VecHash = new HashSet<Vector2>();
            HashSet<int> intHash = new HashSet<int>();
            bool[,] boolArr = new bool[size * 2, size * 2];


        for (int x = -size; x < size; x++) {
            for (int y = -size; y < size; y++) {
                VecHash.Add(new Vector2(x, y));
                intHash.Add(calculateHash(x,y));
                boolArr[x+size, y + size] = true;
            }
        }


        Console.WriteLine("Press enter to start");
        Console.ReadLine();

        int reps = 1000;
        int testSize = 180;
        Stopwatch sw = new Stopwatch();
        while (true) {
            long counter = 0;
            sw.Start();
            for (int i = 0; i < reps; i++)
            {
                counter += runtest(VecHash, testSize);
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedTicks + "\tVecHash items: \t" + counter);
            counter = 0;
            sw.Restart();
            for (int i = 0; i < reps; i++)
            {
                counter += runtest(intHash, testSize);
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedTicks + "\tIntHash items: \t" + counter);
            counter = 0;
            sw.Restart();
            for (int i = 0; i < reps; i++)
            {
                counter += runtest(boolArr, testSize, size);
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedTicks + "\tboolArr items: \t" + counter);
            sw.Reset();
            Console.ReadLine();
        }

    }


    static int runtest(HashSet<Vector2> coll, int size)
    {
        int counter = 0;

        var allrelevant = coll.Where(a => a.x >= -size && a.x < size && a.y >= -size && a.y < size);
        foreach (var item in allrelevant) {
            counter++;

            float tx = item.x;
            float ty = item.y;
        }

        return counter;
    }
    static int runtest(HashSet<int> coll, int size)
    {
        int counter = 0;
        for (int x = -size; x < size; x++)
        {
            for (int y = -size; y < size; y++)
            {
                if (coll.Contains(calculateHash(x, y)))
                {
                    counter++;

                    int tx = x;
                    int ty = y;
                }
            }
        }
        return counter;
    }
    static int runtest(bool[,] coll, int size, int globalSize)
    {
        int counter = 0;
        for (int x = -size; x < size; x++)
        {
            for (int y = -size; y < size; y++)
            {
                if (coll[x+ globalSize, y+ globalSize])
                {
                    counter++;

                    int tx = x;
                    int ty = y;
                }
            }
        }
        return counter;
    }

    public static int calculateHash(float x1, float y1)
    {
        int x = (int)Math.Floor(x1);
        int y = (int)Math.Floor(y1);

        return calculateHash(x, y);
    }

  //[MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int calculateHash(int x, int y) {
        return x + (y << 16);
    }
}

public struct Vector2
{
    public readonly float x;
    public readonly float y;

    public Vector2(float x, float y)
    {
        this.x = x;
        this.y = y;
    }
}

}

1 个答案:

答案 0 :(得分:1)

经典空间/尺寸权衡。 HashSets和其他哈希样式的数据结构必须使用散列算法来提供我们使用它们的O(1)速度。在.NET中,这是通过作为每个对象一部分的.GetHashCode()方法完成的。

这是减速的一部分来自 - 你正在执行一个哈希函数,以及包含Contains及其调用的许多其他函数,包括InternalGetHashCode和许多其他函数。所以你在堆栈上抛出了许多额外的东西,以及它们的状态等等。

因此,你真的不会比这个巨大的2D阵列快得多。

相关问题