我在Web Api 2应用程序中使用自定义缓存实现。此缓存存储数十万个项目,并且可以在单个API请求中读取多达10,000次。
在分析时,我发现每个项目的缓存密钥的实际构建会显着影响整体性能。
.NET分析的结果:
缓存密钥详细信息:
我正在通过散列字符串来构建项目的密钥。 E.g:
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
,因此这应该是构建字符串的最有效方式。有人能发现任何明显的性能提升吗?
修改
根据David和Patryk的评论,另一个考虑因素是我不能硬编码“type”字符串。性能改进需要向后兼容。我必须使用反思。
编辑2:
抱歉,哈希方法意味着返回UInt64
。代码已修复。
编辑3:
将哈希键与友好键存储在性能上没有任何区别。因此,我转向使用GetFriendly()
。谢谢你们。
答案 0 :(得分:2)
看起来你正在使用PostSharp。用于缓存的Their own example在编译时将方法名称生成为字符串 。
您似乎可以同时获得完全限定的类型名称。这将允许昂贵的反射仅在编译时发生。
public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
{
_methodName = method.Name;
_typeName = method.Binding.GetType().Namespace... ..Name; // etc
}
我还会尝试StringBuilder.Append()
vs string.Format()
,看看是否存在性能差异。