reflection速度有多慢
我最近创build了一个接口层来区分DataAccessProvider和业务逻辑层。 通过这种方法,我们可以通过更改Web / App.Config中的值来随时更改DataAccessProvider的select。 (如果需要,可以提供更多的细节)。
无论如何,要做到这一点,我们使用reflection来完成我们可以工作的DataProvider类。
/// <summary> /// The constructor will create a new provider with the use of reflection. /// If the assembly could not be loaded an AssemblyNotFoundException will be thrown. /// </summary> public DataAccessProviderFactory() { string providerName = ConfigurationManager.AppSettings["DataProvider"]; string providerFactoryName = ConfigurationManager.AppSettings["DataProviderFactory"]; try { activeProvider = Assembly.Load(providerName); activeDataProviderFactory = (IDataProviderFactory)activeProvider.CreateInstance(providerFactoryName); } catch { throw new AssemblyNotFoundException(); } }
但是现在我想知道reflection速度有多慢?
在大多数情况下:足够快。 例如,如果使用这个来创build一个DAL包装器对象,通过reflection创build对象的时间相对于连接到networking的时间来说是微不足道的 。 所以优化这将是浪费时间。
如果你在一个紧密的循环中使用reflection,有一些技巧可以改善它:
- generics(使用
where T : new()
和MakeGenericType
的包装器) -
Delegate.CreateDelegate
(对于一个types化的委托;不适用于构造函数) -
Reflection.Emit
。发射 – 铁杆 -
Expression
(如Delegate.CreateDelegate
,但更灵活,适用于构造函数)
但为了您的目的, CreateInstance
完全没问题。 坚持这一点,并保持简单。
编辑:虽然关于相对performance的观点依然存在,而最重要的“衡量”仍然存在,我应该澄清一些上述内容。 有时候……这很重要。 先测量一下。 然而,如果你发现它太慢了,你可能会想看看FastMember ,它会在后台安静地执行所有的Reflection.Emit
代码,给你一个很好的简单的API; 例如:
var accessor = TypeAccessor.Create(type); List<object> results = new List<object>(); foreach(var row in rows) { object obj = accessor.CreateNew(); foreach(var col in cols) { accessor[obj, col.Name] = col.Value; } results.Add(obj); }
这很简单,但会非常快。 在具体的例子中,我提到了一个DAL包装器,如果你正在做这个很多,可以考虑一些类似dapper的东西,它会在后台再次执行所有Reflection.Emit
代码,以便为您提供尽可能快但易于使用的API:
int id = 12345; var orders = connection.Query<Order>( "select top 10 * from Orders where CustomerId = @id order by Id desc", new { id }).ToList();
它比非reflection代码慢。 重要的不是它的速度慢,而是它的速度慢。 例如,如果您在Web环境中使用reflection实例化对象,而预期的并发性可能会上升到10K,则会很慢。
无论如何,它不好提前关心performance。 如果事情变得缓慢,那么如果你正确地devise了一些东西,那么你总是可以加快速度,这样你预期的部分可能在未来需要优化。
如果您需要加速,您可以查看这篇着名的文章:
dynamic…但快速:三只猴子,一只狼和DynamicMethod和ILGenerator类的故事
以下是一些可能有所帮助的链接:
- 这家伙做了一些testing,并提供了一些指标
- MSDN文章“道奇普遍性能陷阱,以快速应用程序”
反思并不慢。 通过reflection调用方法比正常方式慢大约3倍。 如果你只做一次或者在非危急的情况下,这是没有问题的。 如果你在一个时间关键的方法中使用它10000次,我会考虑改变实现。
除了遵循其他答案给出的链接,并确保你没有写“pathalogically坏”的代码,那么对我来说,最好的答案是自己来testing它。
只有你知道瓶颈的位置,你的reflection代码是多less次用户,reflection代码是否在紧密的循环等等。你知道你的商业案例,有多less用户将访问你的网站,性能要求是什么。
但是,鉴于你在这里显示的代码片段,那么我的猜测是reflection的开销不会是一个大问题。
VS.NET的Webtesting和性能testingfunction应该使测量这个代码的性能非常简单。
如果你不使用reflection,你的代码是什么样的? 它会有什么限制? 如果你删除了reflection代码,那么你可能不能忍受自己发现的限制。 这可能是值得尝试devise这个代码没有reflection,看看是否有可能或替代是可取的。
我想我会做一个快速的testing来演示慢速reflection与没有比较。
与reflection
- 通过遍历每个属性和匹配来实例化58个对象
-
总时间: 52254纳秒
while (reader.Read()) { string[] columns = reader.CurrentRecord; CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry(); IEnumerable<PropertyInfo> rawPayFileAttributes = typeof(CdsRawPayfileEntry).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(CustomIndexAttribute))); foreach (var property in rawPayFileAttributes) { int propertyIndex = ((CustomIndexAttribute)property.GetCustomAttribute(typeof(CustomIndexAttribute))).Index; if (propertyIndex < columns.Length) property.SetValue(toReturn, columns[propertyIndex]); else break; } }
没有反思
- 通过创build一个新对象来实例化58个对象
-
总时间: 868纳秒
while (reader2.Read()) { string[] columns = reader2.CurrentRecord; CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry() { ColumnZero = columns[0], ColumnOne = columns[1], ColumnTwo = columns[2], ColumnThree = columns[3], ColumnFour = columns[4], ColumnFive = columns[5], ColumnSix = columns[6], ColumnSeven = columns[7], ColumnEight = columns[8], ColumnNine = columns[9], ColumnTen = columns[10], ColumnEleven = columns[11], ColumnTwelve = columns[12], ColumnThirteen = columns[13], ColumnFourteen = columns[14], ColumnFifteen = columns[15], ColumnSixteen = columns[16], ColumnSeventeen = columns[17] }; }
尽pipe这并不完全公平,因为反思还需要通过reflection创build一个新的对象来检索每个属性的特定属性58 * 18次,但是至less可以提供一些透视。
我一直在做类似的事情,直到我开始玩IoC。 我将使用Spring对象定义来指定数据提供者 – SQL,XML或Mocks!