Я использую пользовательскую реализацию кеша в приложении Web Api 2. Этот кеш хранит сотни тысяч элементов и может быть прочитан от 10 000 раз в одном запросе API.Быстрое создание ключа кэша
При профилировании я обнаружил, что фактическое построение кеша ключей каждого элемента существенно влияет на общую производительность.
Результат от .NET профилирование:
Кэш ключевые детали:
Я здание ключ пункты, путем хэширования строки. Например:
MySystem.MyProject.MyNamespace.MyClass.SomeMethod(44,6948)
Это получает хэшируются в нечто вроде этого, который затем используется в рамках кэширования в качестве ключа (это не больше используется - см EDIT 3):
1bbbfeae-b143-77f2-8381-5ee11f5b9c0c
Очевидно, что я необходимо обеспечить уникальность каждого ключа, но я не могу найти способ улучшить производительность здесь, не введя возможного дублирования.
Ключ строитель:
public class CacheKeyBuilder
{
private MethodInterceptionArgs methodArguments;
public CacheKeyBuilder(MethodInterceptionArgs input)
{
methodArguments = input;
}
// No longer used - refer to EDIT 3
public UInt64 GetHashedKey()
{
return Hash(GetFriendlyKey());
}
public string GetFriendlyKey()
{
if (methodArguments.Arguments.OfType<IList>().Any())
{
throw new ArgumentOutOfRangeException("Cannot create a keys from IList types");
}
var type = methodArguments.Binding.GetType();
var key = String.Format("{0}.{1}.{2}{3}{4}",
type.Namespace,
type.DeclaringType.Name,
methodArguments.Method.Name,
type.UnderlyingSystemType.GenericTypeArguments.Select(x => x.Name).ToList().JoinItems("<", ">", ","),
methodArguments.Arguments.Where(x => x != null).Select(x => x.ToString()).ToList().JoinItems("(", ")", ",")
);
return key;
}
// No longer used - refer to EDIT 3
private UInt64 Hash(string key)
{
UInt64 hashedValue = 3074457345618258791ul;
for (int i = 0; i < key.Length; i++)
{
hashedValue += key[i];
hashedValue *= 3074457345618258799ul;
}
return hashedValue;
}
}
соображение:
- Ключ потребность имена, полное имя типа, дженерик и все значения свойств для обеспечения уникальности.
String.Format()
по существу реализуетStringBuilder
, поэтому это должен быть наиболее эффективный способ построения строк.- Я получил хэширование от this post (Knuth hash?), Которое быстрее, чем мои собственные предыдущие реализации.
Можно ли выявить какие-либо очевидные улучшения в производительности, которые могут быть сделаны?
EDIT:
Еще одно соображение, основанное на Давида и комментарии Patryk, то, что я не могу жесткий код «тип» строка. Улучшения производительности должны быть обратно совместимы. Я должен работать с размышлением.
EDIT 2:
К сожалению, методы хеширования предназначены для возврата UInt64
. Код исправлен.
EDIT 3:
Сохранение ключа хешированной против дружественного ключа не сделал никакой разницы в производительности. Таким образом, я перехожу только к GetFriendly()
. Спасибо usr.
Функция 'Hash' возвращает строку. Если вы собираетесь использовать строку в качестве ключа, просто используйте оригинальную строку с неповрежденной строкой: 'MySystem.MyProject.MyNamespace.MyClass.SomeMethod (44,6948)'. Тем не менее, я думаю, что ваше узкое место, вероятно, находится в 'GetFriendlyKey()'. Я не вижу ваш скриншот профилирования. Могут ли жестко закодированные строки с добавленными параметрами помочь? –
Отражение, вероятно, здесь не помогает ... –
О, и 10 000 запросов в одном вызове API говорят мне, что вам нужно какое-то хранилище контекста, чтобы свести к минимуму это. Кэширование должно быть главным образом _between_ вызовов. –