C#字典在键为struct时性能大打

时间:2018-12-10 04:13:25

标签: c#

我正在编写一个类,该类允许两个不同的索引,每个索引的目标是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],有没有一种方法可以隐式将fromto当作结构,而不必分配它?当变量在堆栈上彼此相邻时,实例化一个新结构似乎很愚蠢。
  • 是否有更好的方法来解决此问题,考虑到Dictionary对结构进行哈希处理可能会导致相当大的开销

还有最后一件事:在发布任何“过早优化”或“这是否实际上会影响您的性能”之前,我确实意识到了这一点。我利用这样的机会从低层次的角度更好地理解C#和.NET,并相信像这样的极端优化案例可以提供很好的知识。

0 个答案:

没有答案