2010-04-22 92 views
2

考虑以下代码:为什么速度不同?

function Foo(ds as OtherDLL.BaseObj) 
    dim lngRowIndex as long 
    dim lngColIndex as long 

    for lngRowIndex = 1 to ubound(ds.Data, 2) 
     for lngColIndex = 1 to ds.Columns.Count 
      Debug.Print ds.Data(lngRowIndex, lngColIndex) 
     next 
    next 
end function 

OK,一点背景知识。参数ds是在引用的ActiveX DLL中定义的OtherDLL.BaseObj类型。 ds.Data是一个变体的二维数组(一维承载数据,另一个承载列索引)ds.Columns是'ds.Data`中的列的集合

假设至少有400行数据, 25列,这个代码大约需要15秒,我的机器上运行的类的令人难以置信的

但是如果我的变量数组复制到一个局部变量,所以:。

function Foo(ds as OtherDLL.BaseObj) 
    dim lngRowIndex as long 
    dim lngColIndex as long 
    dim v as variant 

    v = ds.Data 
    for lngRowIndex = 1 to ubound(v, 2) 
     for lngColIndex = 1 to ds.Columns.Count 
      Debug.Print v(lngRowIndex, lngColIndex) 
     next 
    next 
end function 

整个事情的过程中几乎没有任何显着的时间(基本接近于0)。

为什么?

回答

2

很可能是ds.Data每次访问时都会创建/复制整个数组(例如,通过从数据库中提取数据或其他东西),并且这会花费大量时间。

通过在循环内访问它,您就可以进行数百次这种复制操作。在第二种情况下,您只需将它复制到循环外的局部变量中,然后快速重复使用该数据数百次,而无需再次实际复制它。

这是一个常见且非常重要的优化技术:将任何不必要的工作移出循环,以便尽可能少地执行。只是在你的例子中,当你访问数据时,并不是“显而易见”的,它会做很多额外的工作。

+0

请注意:财产'getters'可以执行计算(甚至有副作用) – 2010-04-22 06:00:49

+0

@Jason Williams。这是我检查的第一件事。吸气剂不会从任何地方获取任何东西。一切都在记忆中。这个getter有一个私有变量,基本上是一个二维数组。这就是它返回的结果。 – AngryHacker 2010-04-22 06:03:13

+0

如果getter是一个返回数组的属性,则每次访问该属性时都会导致整个数组被复制。将其更改为一个返回数组的GetData()方法,并避免此复制。 – 2010-04-22 06:22:33

相关问题