我经常听到反射的使用有多糟糕。虽然我通常避免反思并且很少发现没有它就无法解决我的问题的情况,但我想知道......
对于那些在应用程序中使用反射的人,您是否测量过性能命中,它真的那么糟糕吗?
我经常听到反射的使用有多糟糕。虽然我通常避免反思并且很少发现没有它就无法解决我的问题的情况,但我想知道......
对于那些在应用程序中使用反射的人,您是否测量过性能命中,它真的那么糟糕吗?
Jeff Richter在他的演讲The Performance of Everyday Things中表明,通过反射调用方法比正常调用要慢 1000 倍。
Jeff 的提示:如果需要多次调用该方法,使用一次反射找到它,然后将其分配给一个委托,然后调用委托。
这是。但这取决于你想要做什么。
我使用反射来动态加载程序集(插件),它的性能“惩罚”不是问题,因为该操作是我在应用程序启动期间执行的操作。
但是,如果您在一系列嵌套循环中进行反射,每个循环都带有反射调用,我会说您应该重新访问您的代码:)
对于“几次”操作,反射是完全可以接受的,您不会注意到它有任何延迟或问题。这是一个非常强大的机制,甚至被 .NET 使用,所以我不明白您为什么不应该尝试一下。
反射性能将取决于实现(重复调用应该被缓存,例如:)entity.GetType().GetProperty("PropName")
。由于我每天看到的大部分反射都用于填充来自数据读取器或其他存储库类型结构的实体,因此我决定在反射用于获取或设置对象属性时专门对性能进行基准测试。
我设计了一个我认为是公平的测试,因为它缓存了所有重复调用,并且只缓存了实际的 SetValue 或 GetValue 调用。性能测试的所有源代码都在 bitbucket 中:https ://bitbucket.org/grenade/accessortest 。欢迎和鼓励审查。
我得出的结论是,当反射实现完成时,在一次返回少于 100,000 行的数据访问层中删除反射是不切实际的,并且不会提供明显的性能改进。
上图展示了我的小基准测试的输出,并显示了优于反射的机制,仅在 100,000 次循环标记后才会显着提高。大多数 DAL 一次只返回数百甚至数千行,在这些级别上,反射表现得很好。
如果您不在循环中,请不要担心。
我最相关的经验是编写代码来比较大型对象模型中任何两个相同类型的数据实体的属性。让它工作,尝试它,显然像狗一样跑。
我很沮丧,然后一夜之间意识到,在不改变逻辑的情况下,我可以使用相同的算法来自动生成方法来进行比较,但静态访问属性。完全没有时间为此目的调整代码,并且我有能力对实体与静态代码进行深入的属性比较,只要对象模型发生变化,只需单击按钮即可更新。
我的观点是:在与同事的对话中,我曾多次指出他们对反射的使用可能是自动生成代码以进行编译而不是执行运行时操作,这通常值得考虑。
糟糕的是,您甚至不得不担心 .NET 库在内部为性能关键代码执行的反射。
以下示例已过时 - 在当时(2008 年)是正确的,但很久以前已在更新的 CLR 版本中修复。不过,总的来说,反射仍然是一件有点昂贵的事情!
恰当的例子:您不应该在高性能代码的 lock (C#) / SyncLock (VB.NET) 语句中使用声明为“Object”的成员。为什么?因为 CLR 不能锁定值类型,这意味着它必须进行运行时反射类型检查,以查看您的 Object 是否实际上是值类型而不是引用类型。
与编程中的所有事情一样,您必须平衡性能成本与获得的任何收益。小心使用时,反射是一种非常宝贵的工具。我在 C# 中创建了一个 O/R 映射库,它使用反射来进行绑定。这工作得非常好。大多数反射代码只执行一次,因此对性能的影响很小,但好处很大。如果我正在编写一个新的扇形排序算法,我可能不会使用反射,因为它的扩展性可能很差。
我很感激我在这里没有完全回答你的问题。我的观点是,这并不重要。在适当的地方使用反射。这只是您需要了解如何以及何时使用的另一种语言功能。
与所有事情一样,这一切都是为了评估情况。在DotNetNuke中有一个相当核心的组件FillObject
,它使用反射来填充数据行中的对象。
这是一个相当常见的场景,MSDN 上有一篇文章,使用反射将业务对象绑定到 ASP.NET 表单控件,其中涵盖了性能问题。
除了性能之外,我不喜欢在那个特定场景中使用反射的一件事是它往往会降低快速理解代码的能力,当你认为你也会失去编译时,这对我来说似乎不值得付出努力时间安全,而不是强类型数据集或LINQ to SQL之类的东西。
如果您将反射用于频繁创建对象,则反射会对性能产生显着影响。我开发了基于Composite UI Application Block的应用程序,它严重依赖反射。与通过反射创建对象相关的性能明显下降。
但是在大多数情况下,反射的使用没有问题。如果您只需要检查一些组件,我会推荐Mono.Cecil,它非常轻巧且快速
反射是昂贵的,因为每当您请求与参数列表匹配的方法时,运行时必须进行许多检查。在内部的某个地方,存在循环遍历类型的所有方法、验证其可见性、检查返回类型以及检查每个参数的类型的代码。所有这些东西都需要时间。
当您在内部执行该方法时,会出现一些代码,例如在执行实际目标方法之前检查您是否传递了兼容的参数列表。
如果可能的话,如果将来要不断地重用它,总是建议缓存方法句柄。像所有好的编程技巧一样,避免重复自己通常是有意义的。在这种情况下,不断地查找带有某些参数的方法然后每次都执行它是很浪费的。
在源头周围戳一下,看看正在做什么。
反射不会显着降低应用程序的性能。通过不使用反射,您可能能够更快地完成某些事情,但如果反射是实现某些功能的最简单方法,那么使用它。如果它成为一个性能问题,你总是可以重构你的代码远离反射。
我想你会发现答案是,这取决于。如果你想把它放在你的任务列表应用程序中,这没什么大不了的。如果您想将其放入 Facebook 的持久性库中,这是一件大事。