有些人认为使用dynamic
关键字引入的C#4.0功能与VB的“一切都是对象”功能相同。但是,对动态变量的任何调用都将被转换为委托一次,从那时起,将调用委托。在VB中,当使用Object
时,不应用缓存,并且对非类型化方法的每次调用都涉及大量的底层反射,有时总共会产生高达400倍的性能损失。
是否已将dynamic type delegate-optimization and caching添加到VB无类型方法调用中,或者VB的无类型对象仍然如此慢?
答案 0 :(得分:5)
对Hans Passant提到的earlier referred to article的一些研究和更好的解读,得出以下结论:
IDynamicMetaObjectProvider
,更新VB.NET编译器以识别它; Object
只会在对象实现IDynamicMetaObjectProvider
时使用DLR和方法缓存; 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
属性,已经在不到五十万个对象的中等大小的列表上,后期绑定代码变得如此明显,最终导致整个网站崩溃。事实证明很难追查这个问题,但这是另一个故事。解决此问题后,该网站重新获得了95%的CPU资源。
所以,对于汉斯的问题的答案“你有没有更大的问题需要担心”很简单:这是一个大问题(或者可能是),尤其是。对于那些对使用后期绑定过于粗心的VB程序员。
在这种特殊情况下,很多人都喜欢它们,VB.NET 2010显然没有升级为引入后期绑定,因此,Object
对于不知情者来说仍然是邪恶的,不应该与{{{{1}进行比较1}}。
PS:后期绑定性能问题非常难以追踪,除非您有一个好的性能分析器并且知道编译器在内部如何实现后期绑定。
答案 1 :(得分:2)
答案 2 :(得分:0)
好问题。我猜测答案是“否”,因为MSDN杂志中的this article说VB.Net已经改为支持动态语言运行时,并简要描述了对运行时的更改,但没有提到缓存。
有谁知道更好吗?