我正在编写一个类,该类允许两个不同的索引,每个索引的目标是O(1)。这两个索引当前都使用Dictionary
作为基础结构。
internal class RayCollection
{
private readonly Dictionary<ulong, Ray> idLookup_;
private readonly Dictionary<ProjectionKey, Ray> projectionLookup_;
public RayCollection()
{
idLookup_ = new Dictionary<ulong, Ray>();
projectionLookup_ = new Dictionary<ProjectionKey, Ray>();
}
public void Add(Ray ray)
{
idLookup_.Add(ray.Id, ray);
projectionLookup_.Add(new ProjectionKey(ray.From, ray.To), ray);
}
public Ray this[ulong id]
{
get => idLookup_[id];
}
public Ray this[ulong from, ulong to]
{
get => projectionLookup_[new ProjectionKey(from, to) ];
}
internal struct ProjectionKey
{
ulong From;
ulong To;
public ProjectionKey(ulong from, ulong to)
{
From = from;
To = to;
}
}
}
这可以正常工作,但是使用结构会导致性能下降!用ProjectionKey
编制索引的速度要慢将近130倍。
Method | Mean | Error | StdDev |
----------------- |-----------:|-----------:|-----------:|
GetViaId | 5.823 ns | 0.1801 ns | 0.1769 ns |
GetViaProjection | 646.951 ns | 12.4307 ns | 12.2086 ns |
相当大的开销可能是由于每次调用索引运算符时都必须创建一个ProjectionKey
的新实例引起的,并且我推测更多开销是由于Dictionary
不得不对结构执行查找。无论哪种情况,我都希望尽可能减少这种开销。
那么,我的问题是:
this[ulong from, ulong to]
,有没有一种方法可以隐式将from
和to
当作结构,而不必分配它?当变量在堆栈上彼此相邻时,实例化一个新结构似乎很愚蠢。Dictionary
对结构进行哈希处理可能会导致相当大的开销还有最后一件事:在发布任何“过早优化”或“这是否实际上会影响您的性能”之前,我确实意识到了这一点。我利用这样的机会从低层次的角度更好地理解C#和.NET,并相信像这样的极端优化案例可以提供很好的知识。