有人争辩说,C# 4.0 引入的dynamic
关键字特性与 VB 的“一切都是对象”特性相同。但是,对动态变量的任何调用都将转换为一次委托,从那时起,将调用委托。在 VB 中,使用 时Object
,不应用缓存,并且对非类型化方法的每次调用都涉及大量的底层反射,有时总共会造成高达 400 倍的性能损失。
动态类型委托优化和缓存是否也被添加到 VB 无类型方法调用中,还是 VB 的无类型对象仍然如此缓慢?
有人争辩说,C# 4.0 引入的dynamic
关键字特性与 VB 的“一切都是对象”特性相同。但是,对动态变量的任何调用都将转换为一次委托,从那时起,将调用委托。在 VB 中,使用 时Object
,不应用缓存,并且对非类型化方法的每次调用都涉及大量的底层反射,有时总共会造成高达 400 倍的性能损失。
动态类型委托优化和缓存是否也被添加到 VB 无类型方法调用中,还是 VB 的无类型对象仍然如此缓慢?
一些研究和对Hans Passant 提到的前面提到的文章的更好阅读,得出以下结论:
IDynamicMetaObjectProvider
如果您想显式支持动态,您可以实现,VB.NET 编译器已更新以识别这一点;Object
将只使用 DLR 和方法缓存IDynamicMetaObjectProvider
;IDynamicMetaObjectProvider
,Object
在此类类型或您自己的类型上使用将调用经典的、非缓存的 VB.NET 后期绑定器。有些人(其中包括 Hans Passant,请参阅他的回答)可能想知道为什么后期绑定中的缓存或非缓存可能很重要。实际上,它在 VB 和其他后期绑定技术中都有很大的不同(还记得IQueryInterface
COM 吗?)。
后期绑定归结为一个简单的原则:给定名称及其参数声明,通过Type
接口可用的方法(在 VB 中,方法、属性和一个字段可以看起来相同,使这个过程更慢)。如果您认为方法表是无序的,那么这很容易比单个直接(即类型化)方法调用昂贵得多。
如果您能够一次查找方法,然后将方法指针存储在查找表中,这将大大加快此过程。DLR 中的缓存方法绑定更进一步,如果可能,将方法调用替换为指向实际方法的指针。在第一次调用之后,每次后续调用都会快一个数量级(想想快 200 倍到 800 倍)。
作为一个重要的例子,这里有一些代码可以说明这个问题。如果每个类都有一个.Name
字符串属性,但这些类不共享一个共同的祖先或接口,您可以天真地对任何这些类型的列表进行排序,如下所示:
' in the body of some method '
List<Customers> listCustomers = GetListCustomers()
List<Companies> listCompanies = GetListCompanies()
listCustomers.Sort(MySort.SortByName)
listCompanies.Sort(MySort.SortByName)
' sorting function '
Public Shared Function SortByName(Object obj1, Object obj2) As Integer
' for clarity, check for equality and for nothingness removed '
return String.Compare(obj1.Name, obj2.Name)
End Function
这段代码(至少是类似的)实际上是与我的一个客户一起投入生产的,并用于通常称为 AJAX 回调。如果不手动缓存.Name
属性,已经在不到 50 万个对象的中型列表上,后期绑定代码变得如此明显的负担,最终导致整个站点崩溃。事实证明很难追查到这个问题,但这是另一个故事了。修复此问题后,该站点重新获得了 95% 的 CPU 资源。
所以,汉斯的问题“你没有更大的问题要担心”的答案很简单:这是一个大问题(或可能是),尤其是。给那些对使用后期绑定过于粗心的 VB 程序员。
在这种特殊情况下,以及许多类似的情况下,VB.NET 2010 显然没有升级到引入后期绑定,因此Object
对于不知情的人来说仍然是邪恶的,不应该与dynamic
.
PS:后期绑定性能问题很难追踪,除非你有一个好的性能分析器并且知道后期绑定是如何由编译器内部实现的。
好问题。我猜答案是“否”,因为MSDN 杂志上的这篇文章说 VB.Net 已更改为支持动态语言运行时,并简要描述了运行时的更改,但没有提及缓存。
有没有人更了解?