.NET反射的成本是多少?


210

我不断地听到要使用多么糟糕的反射。虽然我通常会避免反思,很少发现没有它无法解决我的问题的情况,但我想知道...

对于那些在应用程序中使用反射的人,您是否衡量了性能方面的影响,真的那么糟糕吗?


您可能还想看看这个问题。stackoverflow.com/questions/224232/…–
smaclell

1
使用在fastflect.codeplex.com上的api。对于吸气剂/设置器/调用者和其他一些东西,它将加速反射500倍。如果您需要扩展它的来源和信息,也可以找到它的工作方式。
布兰登·摩尔

3
该信息如何在2014年退房?这四年有什么变化吗?
2014年

1
将值分配给实例属性的简单任务,通过反射(PropertyInfo.SetValue(instance,value))进行反射的速度大约比使用直接编码(instance.property = value)慢150倍。这是在.NET 4.0中
Thanasis Ioannidis

Answers:


130

它是。但这取决于您要执行的操作。

我使用反射来动态加载程序集(插件),并且它的性能“惩罚”不是问题,因为该操作是我在应用程序启动期间执行的操作。

但是,如果您要在一系列嵌套循环中进行反射,并且每个循环都需要进行反射调用,那么我想您应该重新访问代码:)

对于“几次”操作,反射是完全可以接受的,您不会注意到任何延迟或问题。这是一个非常强大的机制,甚至.NET都在使用它,所以我不明白为什么不应该尝试一下。


我一直在使用反射来获取方法,当前方法的类名来记录try-catch中的错误。基本上是为了避免在记录错误时对功能名称进行硬编码。我需要担心吗?
Sangram Nandkhile 2015年

@Sangram nope,很好
Karthik AMR

@Sangram不,除非您遇到许多需要不断捕获的错误,否则这应该是另一个问题:)
Martin Marconcini

5
@Sangram虽然反射性能不应该成为您的问题,但似乎您正在尝试以更优雅的方式重新实现普通的旧异常所提供的...
JacekGorgoń

152

杰夫·里希特(Jeff Richter)在他的演讲《日常事物的性能》中指出,通过反射调用方法比正常调用要慢大约1000倍

Jeff的技巧:如果您需要多次调用该方法,请使用一次反射来查找它,然后将其分配给一个委托,然后调用该委托。


18
我也参加了Devscovery,并同意.NET 3.5的这些结果。重新编译.NET 4的Devscovery性能基准程序显示出巨大的改进!成本降低了100倍。.NET 3.5和.NET 4之间使用反射对的typeof()查找是不变
约翰维格尔

61

反射性能将取决于实现(重复调用应被缓存,例如:)entity.GetType().GetProperty("PropName")。由于我每天看到的大多数反射都是用来填充数据读取器或其他存储库类型结构中的实体的,因此我决定在反射用于获取或设置对象属性时专门针对反射进行基准测试。

我设计了一个我认为很公平的测试,因为它可以缓存所有重复的调用,并且只对实际的SetValue或GetValue调用进行一次。性能测试的所有源代码都位于bitbucket中,网址为:https ://bitbucket.org/grenade/accessortest 。欢迎并鼓励进行审查。

我得出的结论是,它不切实际,并且没有提供显着的性能改进来消除数据访问层中的反射,该数据访问层在反射实现完成时一次返回的行数少于100,000。

时间(y)与已填充实体数量(x)的关系图

上图显示了我的小基准测试的输出,并显示了优于反射的机制,只有在100,000个周期后才明显地表现出来。大多数DAL一次仅返回数百行或数千行,在这些级别上,反射性能很好。


9
不必要。您的DAL转换可能仅涉及几千个项目,但要乘以使用您的应用程序(如果是网络)的并发用户,它的总和就好像您要转换一百万个项目一样。如果特定的方法慢100倍,那么在大大小小的集合上速度就会慢很多。慢一点慢一点。
罗伯特·科里特尼克

@RobertKoritnik假设服务器上的Web方法不是异步的
Kurren 2014年

@kurren异步性不会影响反射,但会影响服务器资源。异步Web方法当然可以为更多的用户提供服务,但是反射仍然很慢。反正AFAIK本身就是一个同步过程。另一方面,数据获取将是唯一可以与异步设计完美配合的部分。
罗伯特·科里特尼克

3
图表上的超级方法是什么?与Reflector有什么不同?
布莱恩·



12

我最相关的经验是编写代码来比较大型对象模型中相同类型的任何两个数据实体。可以正常工作,尝试一下,显然像狗一样奔跑。

我很沮丧,然后一夜之间意识到不改变逻辑,我可以使用相同的算法自动生成用于进行比较但静态访问属性的方法。完全不需要花任何时间就可以为此目的修改代码,而且我能够使用静态代码对实体进行深入的属性比较,只要对象模型发生更改,单击按钮即可更新静态代码。

我的观点是:在我与同事的对话中,由于我多次指出,他们对反射的使用可能是为了自动生成代码以进行编译,而不是执行运行时操作,这通常值得考虑。


考虑到Visual Studio具有如此出色的模板支持,这是使用代码生成的一种实用方法
Sebastian

12

没有大规模。我从来没有在桌面开发中遇到过任何问题,除非像Martin指出的那样,除非您在一个愚蠢的位置使用它。我听说很多人对它在桌面开发中的性能有完全非理性的恐惧。

不过,在紧凑型框架(通常是在紧凑型框架中)中,它非常令人厌恶,在大多数情况下,应像瘟疫一样避免使用。我仍然可以不经常使用它,但是我必须非常小心它的应用程序,因为它的乐趣不那么严重。:(


5
+1教给我一个新词:反感。还提到非理性的恐惧。我担心程序员会非理性地恐惧-这表明他们并不真正知道自己在做什么,而只是将自己的所作所为基于其他人告诉他们的事情。咳嗽货物崇拜咳嗽
bsneeze

1
啊货崇拜。现在有一个很好的例子说明人类的行为。
Quibblesome

10

即使对于性能关键代码的.NET库在内部进行的反射,您也必须担心,这已经很糟糕了。

以下示例已过时-当时(2008年)为true,但很早以前已在较新的CLR版本中修复。但是,总体而言,反思仍然是一件昂贵的事情!

恰当的例子:永远不要在高性能代码的锁(C#)/ SyncLock(VB.NET)语句中使用声明为“对象”的成员。为什么?因为CLR无法锁定值类型,所以这意味着它必须进行运行时反射类型检查,以查看您的Object是否实际上是值类型而不是引用类型。


13
公平地说,反射类型检查很快。
吉米

1
对于这种“性能关键代码”,您真的应该从使用.NET开始吗?
Seph 2012年

1
@Seph:.NET的动态/反射部分,否。但是通常的C#/。NET为什么不呢?C ++与C#的加速在应用程序层上是微不足道的(在密集的数学例程中,C ++的速度仍要快几%)。我猜你不是在建议组装...
DeepSpace101,2013年

装箱的值类型(即对象)可以锁定。@BryceWagner是正确的。
Fowl

1
平心而论(对我而言),说答案是“过时的”而不是“简单的废话”更为准确。我对lock(obj)行为的评论在编写时是准确的,但是CLR的实现特定行为早已消失。
McKenzieG1 2014年

5

与编程中的所有事情一样,您必须在性能成本与所获得的所有收益之间进行权衡。谨慎使用反思是一种无价的工具。我在C#中创建了一个O / R映射库,该库使用反射来进行绑定。这非常好用。大部分反射代码仅执行一次,因此对性能的影响很小,但好处却是巨大的。如果我正在编写新的散乱排序算法,则可能不会使用反射,因为它的伸缩性可能很差。

非常感谢,我在这里还没有完全回答您的问题。我的观点是,这并不重要。在适当的地方使用反射。这只是您需要学习如何以及何时使用的另一种语言功能。


3

如果您经常使用反射创建对象,则反射会对性能产生显着影响。我已经基于高度依赖反射的Composite UI Application Block开发了应用程序。与通过反射创建对象有关的性能显着下降。

但是,在大多数情况下,反射的使用没有问题。如果您唯一需要检查的组件,我建议您使用Mono.Cecil,它非常轻巧,快速


3

反射的成本很高,因为在您请求与参数列表匹配的方法时,运行时必须进行许多检查。在内部某个深处,存在代码,该代码遍历类型的所有方法,验证其可见性,检查返回类型,还检查每个参数的类型。所有这些东西都花费时间。

当您在内部执行该方法时,会有一些代码在执行实际的目标方法之前执行一些检查,例如检查是否传递了兼容的参数列表。

如果可能的话,如果将来要继续重用它,总是建议人们缓存该方法句柄。像所有好的编程技巧一样,避免重复自己通常很有意义。在这种情况下,连续查找具有某些参数的方法然后每次都执行将是浪费的。

在源头上戳一下,看看正在做什么。


3

一切都与评估情况有关。在DotNetNuke中,有一个相当核心的组件FillObject,该组件使用反射来填充数据行中的对象。

这是一个相当常见的场景,并且在MSDN上有一篇文章,《使用反射将业务对象绑定到ASP.NET表单控件》涵盖了性能问题。

除了性能,我不喜欢在特定情况下使用反射的一件事是,它倾向于降低快速了解代码的能力,对于我来说,当您认为自己也失去了编译能力时,这似乎不值得付出努力。时间安全而不是强类型数据集或LINQ to SQL之类的


2

反射不会大大降低应用程序的性能。通过不使用反射,您也许可以更快地完成某些事情,但是如果反射是实现某些功能的最简单方法,请使用它。如果变成了性能问题,您始终可以将代码重构为远离反射。


1

我认为您会发现答案取决于它。如果要将其放入任务列表应用程序中,这没什么大不了的。如果要将其放入Facebook的持久性库中,这很重要。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.