【发布时间】:2014-12-03 06:07:13
【问题描述】:
我在 Web Api 2 应用程序中使用自定义缓存实现。此缓存存储数十万个项目,并且可以在单个 API 请求中读取多达 10,000 次。
在分析时,我发现每个项目的缓存键的实际构建显着影响整体性能。
.NET 分析结果:
缓存关键细节:
我正在通过散列字符串来构建项目的密钥。例如:
MySystem.MyProject.MyNamespace.MyClass.SomeMethod(44,6948)
这被散列成这样的东西,然后在缓存框架中用作键(不再使用 - 请参阅编辑 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 哈希?)得到哈希,这比我自己以前的实现要快。
谁能发现任何明显的性能改进?
编辑:
另一个基于 David 和 Patryk 的 cmets 的考虑是我不能硬编码“类型”字符串。性能改进需要向后兼容。我必须使用反射。
编辑 2:
抱歉,哈希方法旨在返回 UInt64。代码已修复。
编辑 3:
存储散列密钥与友好密钥对性能没有影响。因此,我将转向唯一使用GetFriendly()。谢谢楼主。
【问题讨论】:
-
您的
Hash函数返回一个字符串。如果您要使用字符串作为键,则只需使用原始未散列的字符串:MySystem.MyProject.MyNamespace.MyClass.SomeMethod(44,6948)。也就是说,我认为您的瓶颈可能在GetFriendlyKey()。我看不到你的分析截图。附加参数的硬编码字符串会有帮助吗? -
反思在这里可能也无济于事......
-
哦,一个 API 调用中的 10,000 次查找告诉我您需要某种上下文存储来最小化这种情况。缓存应该主要在之间调用。
-
你为什么要散列你生成的密钥?
-
为什么 Hash 的结果与你给出的示例格式(Guid)不匹配?
标签: c# .net performance hash .net-4.5