自动递增抽象基类的typeid

时间:2018-08-04 16:58:59

标签: c# dictionary

所以我有一个Dictionary<Type, ...>,它已经成为一个紧密循环的瓶颈。我想取消使用Type作为键。我很幸运,最终在该词典中作为键的所有类型都实现了我可以更改的特定接口,并且我想将其更改为抽象基类。

我认为我最终想要做的事情是这样的:

public abstract class MyBaseType
{
   public virtual int TypeId { get; }
}

然后,我将以某种方式使从此自动派生的类递增TypeId。这可以自动进行吗?所以我不必为每个数字都专门设置一个数字吗?

我想避免的事情:

public class MyDerived : MyBaseType
{
   public override int TypeId => 0;
}

public class MyDerived2: MyBaseTYpe
{
   public override int TypeId => 1;
} 
...etc

有什么想法吗?

编辑: 是对类型的查找导致了我的瓶颈。将此类型更改为Type之外的类型是否真的可以给我带来什么好处?

我是否很可能是因为GetHashCode()上的Type才成为瓶颈?

再次编辑: 在字典索引运算符中,我将最昂贵的部分缩小到了我认为的正确位置: Profiler

2 个答案:

答案 0 :(得分:0)

我最终做了(非常重复)的工作,将密钥降低到一个整数,并且速度没有得到太大改善。这说明我对执行的工作成本抱有不切实际的期望。我将研究线程化作为查看改进的另一种方法。

答案 1 :(得分:0)

  

这是否可以自动进行?所以我不必为每个数字都专门设置一个数字吗?

否。

  

将其更改为Type之外的其他类型实际上能给我带来什么好处吗?

您为什么不尝试找出答案?设置一个简单的测试来比较不同的关键性能非常简单。

如果您不愿意这样做,则会发现int 的性能比Type键要好;在int的情况下,性能要快两倍以上。

但是该测试最有意义的结果是,在我的机器上,对于int而言,在40毫秒内执行了1 677 000次查找,对于类型而言,在80毫秒内进行了略微查找。这简直是​​令人难以置信的快速(并且不要忘记那些时间也包括测试键查找)。如果这是您的瓶颈,那么您需要开始思考以某种方式并行化您的工作。

基准代码:

static void Main(string[] args)
{
    var d1 = new Dictionary<int, object>();
    var d2 = new Dictionary<Type, object>();
    var keys1 = new List<int>();
    var keys2 = new List<Type>();            
    var counter = 0;
    var types = Assembly.GetAssembly(typeof(int)).GetTypes();

    foreach (var t in types)
    {
        d1.Add(counter, null);
        keys1.Add(counter++);
        d2.Add(t, null);
        keys2.Add(t);
    }

    //warmup run. JITTER
    benchMarkDictionary(d1, keys1);

    //good runs
    for (var repetition = 0; repetition < 10; repetition++)
    {
        Console.WriteLine($"Test #{repetition} --------");
        Console.WriteLine($"int key: {benchMarkDictionary(d1, keys1)}");
        Console.WriteLine($"type key: {benchMarkDictionary(d2, keys2)}");
    }
}

static long benchMarkDictionary<TKey, TValue>(
    Dictionary<TKey, TValue> dict,
    IList<TKey> keys)
{
    var count = dict.Count;
    TValue result = default(TValue);
    var watch = new Stopwatch();
    watch.Start();

    for (var lookups = 0; lookups < count * 1000; lookups++)
    {
        result = dict[keys[lookups % count]];
    }

    watch.Stop();
    Console.WriteLine(result);
    return watch.ElapsedMilliseconds;
}