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

C# Hashset vs Array,是否可以进一步优化?,c#,optimization,C#,Optimization,在我的整个程序中,我有一个如下的代码。一个例子是寻路,我创建动态环境的快照,并使用创建的地图作为aStar算法的基础 由于代码的执行时间会影响使用寻路的最大单元数,因此我希望在这里尽可能优化 (我相信)最佳性能解决方案是: static int runtest(bool[,] coll, int size, int globalSize) { int counter = 0; for (int x = -size; x < size; x++)

在我的整个程序中,我有一个如下的代码。一个例子是寻路,我创建动态环境的快照,并使用创建的地图作为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(bool[,]coll,int-size,int-globalSize)
{
int计数器=0;
for(int x=-size;x
但是,我对使用阵列时浪费的内存量不满意,因此我目前正在使用此解决方案:

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);
        }
    }
static int runtest(HashSet coll,int size)
{
int计数器=0;
for(int x=-size;x=-size&&a.x=-size&&a.yreturn x+(yClassic space/size tradeoff.hashset和其他散列样式的数据结构必须使用散列算法来提供我们使用它们的O(1)速度。在.NET中,这是通过每个对象的.GetHashCode()方法完成的

这就是速度放缓的部分原因——您正在执行一个哈希函数,以及包含和它调用的许多其他函数,包括InternalGetHashCode和许多其他函数。因此,您在堆栈上抛出了一些额外的东西,以及它们的状态,等等


因此,你真的不会比这个巨大的2D数组快很多。

我知道我发布的数组版本可能是最佳版本。我要求的是可能对hashset版本进行小的优化。根据我在你的代码中看到的,实际上没有任何大的优化。实现是相同的,模块化的哈希集实现的开销。您可以使用包含X、Y和自定义哈希函数的自定义ValueType来提高速度。您也可以尝试摆脱下限调用,强制转换为Int本身就可以做到这一点。强制转换为Int会截断该值,这与正值的下限相同,但ceil f或者是负数,我需要正数和负数的相同行为可能一种混合的方法是合适的:默认为数组,如果数组的大小大于某个阈值,则使用哈希集。你能解释一下使用数组时会浪费多少内存吗?@Maarten我将数组用作二维映射。一些字段在上面的方法中,如果在映射的那个位置有什么东西,我会做一些事情。所有设置为false的字段都是浪费空间。哈希集避免了这一点,因为它只存储实际存在的值。数组有多大?是否存在实际内存问题em?@Maarten取决于寻路的起始位置和目标位置。因此,使用锯齿阵列而不是多维阵列,阵列可以是10*10到25000*25000。这是一个容易的胜利。减少了一系列索引超出范围的检查。使用不安全代码会更快。
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;
    }
}