cachingreflection数据
caching来自reflection的昂贵数据的最佳方式是什么? 例如,大多数快速序列化器都会caching这些信息,所以每次遇到相同的types时都不需要反映。 他们甚至可以产生一个dynamic的方法,他们从types中查找。
之前.net 4
传统上,我使用了一个正常的静态字典。 例如:
private static ConcurrentDictionary<Type, Action<object>> cache; public static DoSomething(object o) { Action<object> action; if(cache.TryGetValue(o.GetType(), out action)) //Simple lookup, fast! { action(o); } else { // Do reflection to get the action // slow } }
这泄漏了一些内存,但是因为它只有一个types和types只有一次,只要AppDomain
我没有考虑这个问题。
由于.net 4
但是现在.Net 4引入了用于dynamictypes生成的收集组件 。 如果我曾经在收集的程序集中声明的对象上使用DoSomething
,程序集将永远不会被卸载。 哎哟。
那么在.net 4中caching每种types信息的最佳方式是什么? 我能想到的最简单的解决scheme是:
private static ConcurrentDictionary<WeakReference, TCachedData> cache.
但IEqualityComparer<T>
我不得不使用它会performance得很奇怪,也可能违反合同。 我不确定查找速度有多快。
另一个想法是使用到期超时。 可能是最简单的解决scheme,但感觉有点不雅。
在types被作为generics参数提供的情况下,我可以使用不应该遭受这个问题的嵌套generics类。 但是如果这个types是在一个variables中提供的话,他就不能工作。
class MyReflection { internal Cache<T> { internal static TData data; } void DoSomething<T>() { DoSomethingWithData(Cache<T>.data); //Obviously simplified, should have similar creation logic to the previous code. } }
更新 :我刚刚有一个想法是使用Type.AssemblyQualifiedName
作为关键。 这应该唯一标识这种types,而不会将其保存在内存中。 我甚至可能在这个string上使用引用标识。
这个解决scheme仍然存在的一个问题是,caching的值也可能保持对该types的引用。 如果我使用了一个弱引用,那么在程序集卸载之前,它很可能会过期。 我不确定从一个弱引用中获得一个正常的引用是多么便宜。 看起来我需要做一些testing和基准testing。
在这种情况下ConcurrentDictionary<WeakReference, CachedData>
不正确。 假设我们试图cachingtypes为T的信息,所以WeakReference.Target==typeof(T)
。 CachedData最有可能也会包含typeof(T)
引用。 作为ConcurrentDictionary<TKey, TValue>
将项存储在Node<TKey, TValue>
的内部集合中Node<TKey, TValue>
您将拥有强引用链: ConcurrentDictionary
实例 – > Node
实例 – > Value
属性( CachedData
实例) – > typeof(T)
。 一般情况下,当值可以引用它们的键时,使用WeakReference避免内存泄漏是不可能的。
有必要增加对ephemerons的支持,使这种情况下可能没有内存泄漏。 幸运的是,.NET 4.0支持它们,并且我们有ConditionalWeakTable<TKey, TValue>
类。 这似乎是介绍它的原因是接近你的任务。
这种方法也可以解决您的更新中提到的问题,因为types只会在程序集加载的时候才会生效。
你应该检查一下codeplex http://fasterflect.codeplex.com/上更快的转换库;
你可以使用普通的reflectiondynamic生成新的代码,然后发出/编译它,然后caching编译的版本。 我认为可收集的assembly想法是有希望的,以避免内存泄漏,而不必从一个单独的appdomain加载/卸载。 但是,内存泄漏应该可以忽略,除非你正在编译数百种方法。
以下是关于在运行时dynamic编译代码的博文: http : //introspectingcode.blogspot.com/2011/06/dynamically-compile-code-at-runtime.html
下面是我以前用来存储MethodInfo / PropertyInfo对象的一个类似的并发字典方法,它似乎更快,但我认为这是旧版本的Silverlight。 我相信.Net有它自己的内部reflectioncaching,使它不必要的。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.Collections.Concurrent; namespace NetSteps.Common.Reflection { public static class Reflection { private static ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>> reflectionPropertyCache = new ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>>(); public static List<PropertyInfo> FindClassProperties(Type objectType) { if (reflectionPropertyCache.ContainsKey(objectType)) return reflectionPropertyCache[objectType].Values.ToList(); var result = objectType.GetProperties().ToDictionary(p => p.Name, p => p); reflectionPropertyCache.TryAdd(objectType, result); return result.Values.ToList(); } } }
我可能会在这里说明这一点,但是:
不要caching提供者通常将数据序列化到源?
那么反序列化过程肯定会比仅仅反映一个新实例更昂贵?
还是我错过了什么?
而且围绕着拳击和拆箱的时间成本的整个争论……不知道是否真的重要。
编辑:
这个怎么样(希望这个问题解释得更好一点)…
Dictionary<string, Type> typecache = new Dictionary<string, Type>(); // finding a type from say a string that points at a type in an assembly not referrenced // very costly but we can cache that Type myType = GetSomeTypeWithReflection(); typecache.Add("myType", myType); // creating an instance you can use very costly MyThingy thingy = Activator.CreateInstance(typecache["myType"]);
你想caching“thingy”?