How costly is .NET reflection?
我经常听到反射效果有多差。虽然我通常避免反思,很少发现没有它是不可能解决我的问题的情况,但我想知道…
对于那些在应用程序中使用了反射的人,您是否测量了性能命中率,以及它是否真的如此糟糕?
JeffRichter在他的《日常事物的表现》一书中指出,通过反射调用方法比通常调用方法慢1000倍。
Jeff的提示:如果需要多次调用该方法,请使用反射一次找到它,然后将其分配给委托,然后调用委托。
它是。但这取决于你想做什么。
我使用反射来动态加载程序集(插件),它的性能"惩罚"不是问题,因为操作是我在应用程序启动期间所做的。
但是,如果您在一系列嵌套循环中进行反射,每个循环上都有反射调用,那么我建议您重新访问代码:)
对于"两次"操作,反射是完全可以接受的,并且您不会注意到它的任何延迟或问题。它是一个非常强大的机制,甚至被.NET使用,所以我不明白为什么你不应该尝试它。
反射性能将取决于实现(应缓存重复调用,例如:
我设计了一个测试,我认为它是公平的,因为它缓存所有的重复调用,并且只缓存实际的setValue或getValue调用的倍。性能测试的所有源代码都在bitback中:https://bitback.org/grenate/accessortest。欢迎并鼓励进行审查。
我得出的结论是,在一个数据访问层中删除反射是不实际的,也没有提供显著的性能改进,该数据访问层在反射实现完成后返回的行数少于100000行。
上面的图表展示了我的小基准的输出,并且显示了优于反射的机制,只有在100000个周期标记之后才会如此明显。大多数DAL一次只返回几百或数千行,在这些级别上,反射执行得很好。
如果你不在一个循环中,不要担心它。
不是大规模的。我从来没有在桌面开发中遇到过这个问题,除非,正如马丁所说,你在一个愚蠢的地方使用它。我听说很多人对它在桌面开发中的性能有完全不合理的担心。
不过,在紧凑的框架中(我通常在其中),这是一种诅咒,在大多数情况下应该像避免瘟疫一样避免。我仍然可以不经常使用它,但我必须非常小心使用它的应用程序,这样就不那么有趣了。:(
我最相关的经验是编写代码来比较大型对象模型属性中同一类型的任何两个数据实体。很明显,它起作用了,试过了,跑得像条狗。
我很沮丧,然后一夜之间意识到,如果不改变逻辑,我可以使用相同的算法自动生成方法进行比较,但静态访问属性。为了实现这一目的,完全不需要花费时间来调整代码,并且我能够对实体与静态代码进行深入的属性比较,静态代码可以在对象模型更改时单击按钮进行更新。
我的观点是:在与同事的对话中,因为我多次指出,他们使用反射可以自动生成代码来编译,而不是执行运行时操作,这通常是值得考虑的。
对于性能关键的代码,即使是.NET库在内部所做的反射,也要担心,这已经够糟糕的了。
下面的例子已经过时了——在当时是真的(2008年),但很久以前在更新的clr版本中就已经修复了。不过,一般来说,反思仍然是一件有些昂贵的事情!
举例来说:在高性能代码的lock(c)/synclock(vb.net)语句中,不应使用声明为"object"的成员。为什么?因为clr无法锁定值类型,这意味着它必须执行运行时反射类型检查,以查看对象是否实际上是值类型而不是引用类型。
与编程中的所有事情一样,您必须平衡性能成本和获得的任何好处。在小心使用时,反射是一种非常宝贵的工具。我在C中创建了一个O/R映射库,它使用反射进行绑定。这工作得非常好。大多数反射代码只执行一次,因此任何性能影响都很小,但好处是非常大的。如果我正在编写一个新的扇形排序算法,我可能不会使用反射,因为它的伸缩性可能很差。
我很感激我没有完全回答你的问题。我的观点是这并不重要。在适当的地方使用反射。它只是另一种语言特性,您需要学习如何以及何时使用。
反射是昂贵的,因为每当您请求与参数列表匹配的方法时,运行时必须进行许多检查。在内部深处的某个地方,代码存在,它循环一个类型的所有方法,验证其可见性,检查返回类型,还检查每个参数的类型。所有这些东西都需要时间。
当您在内部执行该方法时,会有一些代码执行一些操作,比如检查您在执行实际目标方法之前传递了一个兼容的参数列表。
如果可能的话,如果将来要继续重用方法句柄,建议始终缓存该方法句柄。像所有好的编程技巧一样,避免重复自己通常是有意义的。在这种情况下,使用某些参数连续查找方法,然后每次都执行它是浪费的。
深入调查消息来源,看看正在做什么。
如果将反射用于频繁的对象创建,反射可能会对性能产生显著的影响。我已经开发了基于复合UI应用程序块的应用程序,它严重依赖于反射。与通过反射创建对象相关的性能明显下降。
但是在大多数情况下,反射的使用没有问题。如果你只需要检查一些组件,我推荐Mono.Cecil,它非常轻便和快速
就像所有的事情一样,这都是关于评估情况的。在dotnetnuke中,有一个相当核心的组件,叫做
这是一个非常常见的场景,有一篇关于msdn的文章,使用反射将业务对象绑定到涵盖性能问题的ASP.NET表单控件。
撇开性能不谈,我不喜欢在这种特定的场景中使用反射,因为它往往会降低快速浏览代码的能力,对我来说,当您认为与强类型数据集或类似Linq-to-SQL的数据集相比,您也会失去编译时的安全性时,这似乎不值得付出努力。
反射不会显著降低应用程序的性能。不使用反射也许可以更快地完成某些事情,但是如果反射是实现某些功能最简单的方法,那么就使用反射。如果反射成为性能问题,您可以随时重构代码以避免反射。
我想你会发现答案是,这要看情况而定。如果你想把它放到你的任务列表应用程序中,那就没什么大不了的了。如果你想把它放在Facebook的持久性库中,这是一件大事。