Запрос комментариев: быстрый хешированный базовый класс для диктонарных ключей - PullRequest
1 голос
/ 07 августа 2010

В одном из моих приложений я должен использовать множество диктонар с пользовательскими объектами в качестве ключей. Чтобы повысить производительность поисков, я реализую базовый класс, который переопределяет GetHashCode. Это похоже на работу, но почему-то у меня все еще плохое предчувствие, поэтому я решил опубликовать свой код и буду благодарен за любые советы или комментарии. (Боже мой, я забыл код: D)

abstract class FastHashed
{
    private static Dictionary<Type,ulong> _instanceCounters = new Dictionary<Type,ulong>();

    private int hash;

    protected FastHashed()
    {
        Type instanceType = this.GetType();
        if(! _instanceCounters.ContainsKey(instanceType)) _instanceCounters.Add(instanceType,0);  
        this.hash = ((instanceType.ToString())+(_instanceCounters[instanceType]++.ToString())).GetHashCode();
    }

    public override int  GetHashCode()
    {
         return hash;
    }
}

Редактировать: Не связывайтесь с хэшированием, если это не нужно. Это «решение» медленнее и менее надежно, чем стандартное GetHashCode ().

Edit: Я провел некоторое тестирование производительности с помощью профилировщика Equatec и простого консольного приложения.

Программа класса { статическое чтение только в циклах = 50000; статический словарь objectsDict = new Dictionary (); статический словарь foosDict = new Dictionary ();

    static void Main(string[] args)
    {

        foo[] foos = new foo[cycles];
        object[] objects = new object[cycles];


        for (int i = 0; i < cycles; i++)
        {
            foos[i] = new foo();
            objects[i] = new object();
            foosDict.Add(foos[i], i);
            objectsDict.Add(objects[i], i);
        }

        ObjectHash(objects);
        FooHash(foos);

    }

    static void ObjectHash(Object[] objects)
    {
        int value; 
        for (int i = 0; i < cycles; i++)
        {
            value = objectsDict[objects[i]];
        }

    }
    static void FooHash(foo[] foos)
    {
        int value;
        for (int i = 0; i < cycles; i++)
        {
            value = foosDict[foos[i]];
        }
    }

    class foo
    {
        private readonly int _hash;
        public foo()
        {
            _hash = this.GetHashCode();
        }
        public override int GetHashCode()
        {
            return _hash;
        }
    }
}

Результаты: - FooHash 26 774 мс - ObjectHash 7 мс

Очевидно, что по умолчанию GetHashCode является лучшим выбором.

Ответы [ 3 ]

2 голосов
/ 07 августа 2010

Вы можете пометить хеш-переменную readonly.

Но, честно говоря, в C #, где у вас есть единичное наследование, не всегда разумно "тратить" наследование на реализацию такого специфического поведения. Предположим, вы вдруг захотите наследовать от базового класса, который «что-то» делает. Сохраняйте наследование классов в целях моделирования, а не для реализации деталей.

2 голосов
/ 07 августа 2010
  1. Это не потокобезопасно.
  2. Если вас интересует только равенство ссылок, почему у вас разные счетчики для разных типов?

Если все, что вы хотитесостоит в том, чтобы предотвратить вычисление хэшей несколько раз, почему бы не сделать что-то подобное (или вариант с обобщениями, если словарь будет содержать объекты только определенного типа):

  public class ObjectWithCachedHashCode : IEquatable<ObjectWithCachedHashCode>
    {
        private int _cachedHashCode;

        public object Object { get; private set; }

        public ObjectWithCachedHashCode(object obj)
        {
            Object = obj;
            _cachedHashCode = obj.GetHashCode();
        }

        public override int GetHashCode()
        {
            return _cachedHashCode;
        }

        public bool Equals(ObjectWithCachedHashCode other)
        {
            return other!=null && Object.Equals(other.Object);
        }

        public override bool Equals(object other)
        {
            return Equals(other as ObjectWithCachedHashCode);
        }


    }

Редактировать: Сделан класс совместимым со словарем

0 голосов
/ 07 августа 2010

Насколько я вижу, это просто функционально эквивалентно реализации по умолчанию для object.GetHashCode (), за исключением того, что он медленнее и не поточнобезопасен.Что делает Fast Hash быстрым?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...