根据我的特工所处的位置及其旋转,我需要确定距墙的距离。由于此函数需要一点时间并且需要多次调用,因此我的想法是通过离散化位置x和y以及角度来存储距离。
因此,我的函数的调用方式如下:
float GetWallDistance(int x, int y, int angle)
{
return CalcWallDistance(x, y, angle);
}
其中x和y的范围是0到500,角度范围是0到360。我的第一个想法是将其存储在多维数组中,如下所示:
使用float[,,] saveArray = new float[500, 500, 360];
float GetWallDistance(int x, int y, int angle)
{
float distance = 0;
if(saveArray[x, y, angle] == 0)
{
distance = CalcWallDistance(x, y, angle);
saveArray[x, y, angle] = distance;
}
else
{
distance = saveArray[x, y, angle];
}
return distance;
}
这极大地缩短了计算时间,但是这里的问题是saveArray占用了很大的内存,并且代理很可能不会遍历整个500 x 500 x 360搜索空间。因此,大量内存将一无所获。
因此,我使用字典来更有效地存储数据,如下所示:
使用Dictionary<double, float> saveDictionairy = new Dictionary<double, float>();
float GetWallDistance(int x, int y, int angle)
{
double key = (double)x * 1000 + (double)y + (double)angle/1000
float distance = 0;
if(!saveDictionairy.TryGetValue(key, out distance))
{
distance = CalcWallDistance(x, y, angle);
saveDictionairy.Add(key, distance);
}
return distance;
}
(我尝试使用字符串作为字典的键,但似乎将x,y和angle串联显然要花费相当长的时间)
此方法的确确实提高了内存效率,但相对于索引多维数组,使用键项的字典的查找时间增加了很多。
有人知道如何以一种易于查找的方式有效地存储数据吗?
答案 0 :(得分:3)
.NET Dictionary
使用快速算法,但开销仍然很高。我曾尝试过使其速度更快。我发现通过删除不需要的内容并进行其他设计更改,可以使速度提高6倍。
例如,Dictionary
使用模运算符将哈希码映射到存储桶。 %
出奇地慢。我认为这需要31个CPU周期。当我将其替换为hashCode & bucketCountMask
时,其中存储桶数为2的幂,而bucketCountMask
为buckets.Length - 1
时,我立即实现了巨大的性能提升。
我还删除了对删除项目和迭代器version
功能的支持。我直接公开了slots
数组,以便调用者可以直接更改其中的数据。
此自定义类型的速度更快,因为它更符合我的需求,并且API的使用难度更大。
GitHub上的 .NET代码包含DictionarySlim
类型供内部使用。也许您可以使用它。
答案 1 :(得分:2)
从当前列出的选项来看,就性能和内存分配而言,矩阵方法似乎是最好的选择。
我已经运行了以下基准测试:
[Benchmark(Baseline = true)]
public void MatrixTest()
{
// float[,,] saveArray = new float[501, 501, 361];
for (int x = 0; x <= 500; x++)
for (int y = 0; y <= 500; y++)
for (int angle = 0; angle <= 360; angle++)
if (saveArray[x, y, angle] == 0) saveArray[x, y, angle] = 42;
}
[Benchmark]
void IntKeyDictionaryTest()
{
// Dictionary<int, float> saveDictionary = new Dictionary<int, float>();
for (int x = 0; x <= 500; x++)
for (int y = 0; y <= 500; y++)
for (int angle = 0; angle <= 360; angle++)
{
int key = (x << 18) | (y << 9) | (angle);
if (!saveDictionary.TryGetValue(key, out float d)) saveDictionary[key] = 42;
}
}
[Benchmark]
void DoubleKeyDictionaryTest()
{
// Dictionary<double, float> saveDictionary = new Dictionary<double, float>();
for (int x = 0; x <= 500; x++)
for (int y = 0; y <= 500; y++)
for (int angle = 0; angle <= 360; angle++)
{
double key = (double)x * 1000 + (double)y + (double)angle / 1000l;
if (!saveDictionary.TryGetValue(key, out float d)) saveDictionary[key] = 42;
}
}
具有以下结果:
Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
------------------------ |------------:|----------:|----------:|------:|--------:|------------:|------------:|------------:|--------------------:|
MatrixTest | 727.9 ms | 5.733 ms | 5.363 ms | 1.00 | 0.00 | - | - | - | - |
IntKeyDictionaryTest | 4,682.1 ms | 12.017 ms | 11.241 ms | 6.43 | 0.05 | - | - | - | - |
DoubleKeyDictionaryTest | 12,804.1 ms | 66.425 ms | 62.134 ms | 17.59 | 0.17 | - | - | - | - |
因此,我知道x,y和angle可以分别用9位表示的事实,我设法为您的字典提供了一个更有效的键=>总共27bits可以容纳一个int。 无论如何,矩阵方法似乎是赢家。