我不断地听到要使用多么糟糕的反射。虽然我通常会避免反思,很少发现没有它无法解决我的问题的情况,但我想知道...
对于那些在应用程序中使用反射的人,您是否衡量了性能方面的影响,真的那么糟糕吗?
我不断地听到要使用多么糟糕的反射。虽然我通常会避免反思,很少发现没有它无法解决我的问题的情况,但我想知道...
对于那些在应用程序中使用反射的人,您是否衡量了性能方面的影响,真的那么糟糕吗?
Answers:
它是。但这取决于您要执行的操作。
我使用反射来动态加载程序集(插件),并且它的性能“惩罚”不是问题,因为该操作是我在应用程序启动期间执行的操作。
但是,如果您要在一系列嵌套循环中进行反射,并且每个循环都需要进行反射调用,那么我想您应该重新访问代码:)
对于“几次”操作,反射是完全可以接受的,您不会注意到任何延迟或问题。这是一个非常强大的机制,甚至.NET都在使用它,所以我不明白为什么不应该尝试一下。
反射性能将取决于实现(重复调用应被缓存,例如:)entity.GetType().GetProperty("PropName")
。由于我每天看到的大多数反射都是用来填充数据读取器或其他存储库类型结构中的实体的,因此我决定在反射用于获取或设置对象属性时专门针对反射进行基准测试。
我设计了一个我认为很公平的测试,因为它可以缓存所有重复的调用,并且只对实际的SetValue或GetValue调用进行一次。性能测试的所有源代码都位于bitbucket中,网址为:https ://bitbucket.org/grenade/accessortest 。欢迎并鼓励进行审查。
我得出的结论是,它不切实际,并且没有提供显着的性能改进来消除数据访问层中的反射,该数据访问层在反射实现完成时一次返回的行数少于100,000。
上图显示了我的小基准测试的输出,并显示了优于反射的机制,只有在100,000个周期后才明显地表现出来。大多数DAL一次仅返回数百行或数千行,在这些级别上,反射性能很好。
我最相关的经验是编写代码来比较大型对象模型中相同类型的任何两个数据实体。可以正常工作,尝试一下,显然像狗一样奔跑。
我很沮丧,然后一夜之间意识到不改变逻辑,我可以使用相同的算法自动生成用于进行比较但静态访问属性的方法。完全不需要花任何时间就可以为此目的修改代码,而且我能够使用静态代码对实体进行深入的属性比较,只要对象模型发生更改,单击按钮即可更新静态代码。
我的观点是:在我与同事的对话中,由于我多次指出,他们对反射的使用可能是为了自动生成代码以进行编译,而不是执行运行时操作,这通常值得考虑。
没有大规模。我从来没有在桌面开发中遇到过任何问题,除非像Martin指出的那样,除非您在一个愚蠢的位置使用它。我听说很多人对它在桌面开发中的性能有完全非理性的恐惧。
不过,在紧凑型框架(通常是在紧凑型框架中)中,它非常令人厌恶,在大多数情况下,应像瘟疫一样避免使用。我仍然可以不经常使用它,但是我必须非常小心它的应用程序,因为它的乐趣不那么严重。:(
即使对于性能关键代码的.NET库在内部进行的反射,您也必须担心,这已经很糟糕了。
以下示例已过时-当时(2008年)为true,但很早以前已在较新的CLR版本中修复。但是,总体而言,反思仍然是一件昂贵的事情!
恰当的例子:永远不要在高性能代码的锁(C#)/ SyncLock(VB.NET)语句中使用声明为“对象”的成员。为什么?因为CLR无法锁定值类型,所以这意味着它必须进行运行时反射类型检查,以查看您的Object是否实际上是值类型而不是引用类型。
如果您经常使用反射创建对象,则反射会对性能产生显着影响。我已经基于高度依赖反射的Composite UI Application Block开发了应用程序。与通过反射创建对象有关的性能显着下降。
但是,在大多数情况下,反射的使用没有问题。如果您唯一需要检查的组件,我建议您使用Mono.Cecil,它非常轻巧,快速
一切都与评估情况有关。在DotNetNuke中,有一个相当核心的组件FillObject
,该组件使用反射来填充数据行中的对象。
这是一个相当常见的场景,并且在MSDN上有一篇文章,《使用反射将业务对象绑定到ASP.NET表单控件》涵盖了性能问题。
除了性能,我不喜欢在特定情况下使用反射的一件事是,它倾向于降低快速了解代码的能力,对于我来说,当您认为自己也失去了编译能力时,这似乎不值得付出努力。时间安全而不是强类型数据集或LINQ to SQL之类的。