Подтвердить что ты не робот

Более быстрая альтернатива, чем словарь <Тип, X>?

Я создаю библиотеку, в которой я тестирую производительность. В нем я генерирую a Dictionary<Type, X> один раз. Элементы в настоящее время вставлены в случайном порядке. Словарь остается неизменным во время жизни приложения.

Затем он часто используется для поиска элементов. Поиск является одним из больших узких мест в библиотеке.

Да, я микроуправляю, но учиться. Мне интересно, есть ли лучший способ получить производительность поиска?

Обновление

Я использовал dotTrace для измерения производительности. Отчет + dotTrace находится на моем домашнем компьютере, поэтому у меня нет отчета здесь (возможно, он был загружен где-то в другом месте).

Я использовал тесты, найденные здесь: https://github.com/danielpalme/IocPerformance

Определение словаря находится здесь: https://github.com/jgauffin/Griffin.Container/blob/master/Source/Griffin.Container/ContainerBase.cs

(я создал контейнер в последнюю пятницу, не ожидаю слишком многого)

Update2

Performance breakdown

Dictionary.TryGetValue занимает полностью 101 мс Resolve (всего 251 мс), что составляет 40,2%, если я правильно интерпретировал числа.

4b9b3361

Ответ 1

Тест производительности для контейнеров IoC от Дэниел Пальме (но и другие) немного вводит в заблуждение, поскольку эталонный анализ разрешает очень мелкие графические объекты из контейнера (хотя он явно показывает, что различия в производительности между контейнерами являются большими). Это нереально, потому что большинство приложений (которые используют DI правильно) будут иметь графы объектов, которые содержат досы объектов. При этом разрешается разрешать только корневой объект, и когда контейнер правильно написан, это означает, что в большинстве ситуаций (или, самое большее, несколько) вы будете иметь только один вызов Dictionary<T,V>.TryGetValue per (web) запроса, Из-за этого производительность Dictionary<T, V> не является проблемой.

Я полагаю, что большая часть затрат на производительность Dictionary<T,V>, где TKey равна System.Type, связана с затратами на создание генерации хеш-кода для данного Type. Каждый раз, когда вы вызываете TryGetValue, необходимо вызвать Type.GetHashCode() . GetHashCode является виртуальным (не может быть встроенным), и этот метод вызывает 3 других виртуальных метода. В конце статический (внешний) вызов выполняется в RuntimeHelpers.GetHashCode(key).

Другими словами, вы могли бы оптимизировать производительность для написания определенного (не общего) словарного класса, который использует Type в качестве ключа и вместо вызова Type.GetHashCode() вы должны называть RuntimeHelpers.GetHashCode(key).

ОБНОВЛЕНИЕ (2013-04-05):

Несколько месяцев назад я попытался улучшить производительность контейнера DI, который я поддерживаю, и я играл с оптимизацией словарной части. Я написал свой собственный словарь, который напрямую вызвал RuntimeHelpers.GetHashCode(key) (и пропустил виртуальные вызовы), но в итоге производительность растет там, где такая небольшая (около 1% в тестах Palme), что я решил вернуть эти изменения кода. Поэтому мое нынешнее понимание заключается в том, что реальные затраты на производительность с Dictionary<Type, X> - это все, что происходит внутри RuntimeHelpers.GetHashCode(key).

Ответ 2

Если тип определяется временем компиляции, вы можете попытаться реализовать его следующим образом:

static class ValueFor<T>
{
  // you get another field per type T
  public static X X { get; private set; }

  internal static SetUpValue(X value) { X = value; }
}

Просто используйте это.

var myIntX = ValueFor<int>.X;