5

我有一个使用几乎所有 UDF 的 Excel 模型。比如说,120 列和 400 多行。计算是先垂直然后水平完成的——首先完成第 1 列的所有计算,然后第 1 列的最终输出是第 2 列的输入,依此类推。在每一列中,我调用大约六个或七个 UDF调用其他 UDF。UDF 通常输出一个数组。

每个 UDF 的输入是一些变量,一些范围变量,一些双精度数。范围变量在访问其内容之前在内部转换为数组。

我的问题如下,我可以在没有 UDF 的情况下构建 Excel 模型,并且当我运行模拟时,我可以在 X 小时内完成所有计算。当我使用 UDF 时,模拟时间是 3X 小时或更长。(要回答这个显而易见的问题,是的,我需要使用 UDF,因为如果我想对模型进行一些小的更改(比如添加另一种资产类型(它是一个财务模型)),则需要将近一天的时间来重新制作模型如果没有 UDF 来适应新的法律/财务结构,使用 UDF 大约需要 20 分钟来适应不同的财务结构。)

无论如何,我已经关闭了屏幕更新,函数中没有复制和粘贴,Variant 类型的使用最少,所有数据都包含在一张表中,我在获取内容之前将所有范围类型变量转换为数组.

除了获得更快的计算机或同等设备以使 VBA 代码/Excel 文件运行得更快之外,我还能做什么?请让我知道这是否需要更多说明。

谢谢!

4

5 回答 5

4

几个一般提示。

  1. 发挥你的作用,找出真正的瓶颈在哪里。有关在 excel中使用计时器的信息,请参阅此问题。我敢肯定那里有 VBA 分析器......但你可能不需要走那么远。(注意:首先使用一个数据单元格执行此操作......)

  2. 考虑一下您的设计... 400x120 单元格的数据并不多。它需要几个小时,这一定很痛苦。(在过去,我在等待 1,000 次VLOOKUPS()返回后就破解了它)无论如何,也许不是拥有一堆 UDF,为什么不拥有一个简单的子例程来for..each通过范围并执行您需要它做的事情。48,000 个细胞可能需要几秒钟或几分钟。然后,您可以将子例程与用户的按钮或菜单项相关联。

出于兴趣,我快速查看了选项 2 并创建了 MyUDF(),使用 subDoMyUDF()调用它来进行活动选择对我来说比在每个单元格中都有 UDF 快 10 倍。

Option Explicit



Function MyUDF(myVar As Variant) As Variant
  MyUDF = myVar * 10
End Function

Sub DoMyUDF()
  Dim r As Range
  Dim c As Variant

  Dim t As Single
  t = Timer


  If TypeName(Selection) <> "Range" Then
    Exit Sub
  End If


  Set r = Selection.Cells

  Application.DisplayStatusBar = True

  For Each c In r
    c.Value = MyUDF(c.Value)

    Application.StatusBar = "DoMyUDF(): " & Format(Timer - t, "#0.0000ms")
  Next

  Debug.Print "DoMyUDF(): " & Format(Timer - t, "#0.0000ms")

End Sub

如果您MyUDF()用 UDF 替换,这可能只会为您节省 4.5 分钟......但您可能还可以建立其他一些经济体。尤其是当您一遍又一遍地重复相同的计算时。

于 2009-08-18T15:18:59.710 回答
4

Excel 处理 UDF 的方式存在减速错误。每次计算 UDF 时,Excel 都会刷新 VBE 标题栏(您可以看到它闪烁)。对于大量 UDF,这非常慢。在手动计算模式下绕过非常简单:只需使用 Application.Calculate 之类的东西从 VBA 启动计算(您可以使用 OnKey 捕获 F9 等)。

有关更多详细信息,请参阅http://www.decisionmodels.com/calcsecretsj.htm 。

于 2009-12-05T09:16:39.103 回答
3

您是否考虑过用宏替换 UDF(每个输出单元调用一次),该宏可以在循环中对一系列单元进行操作?

UDF 设置/拆卸非常缓慢,每个 UDF 调用与其他 UDF 共同执行的任何操作(例如,从重叠输入中读取)都会变得额外工作。

这样做我已经能够将性能提高 10-50 倍 - 不到一个月前的情况涉及一个包含 4000-30000 个 UDF 调用的电子表格,将它们替换为在几个命名范围上运行的单个宏。

于 2009-12-05T09:40:05.647 回答
2

确保从 VBA 而不是从电子表格开始重新计算,请参阅http://msdn.microsoft.com/en-us/library/aa730921.aspx#Office2007excelPerf_Overview 和有关 Faster VBA User-Defined Functions 的部分。那就是 Application.Calculate 比在电子表格中按 F9 快得多(在我的测试用例中是 100 倍)。

于 2010-01-28T08:58:02.857 回答
2

控制和最小化重新计算

wks.EnableCalculation = False

或者

Application.Calculation = xlCalculationManual

此外,尽量减少 VBA 和工作簿之间的交换。一次读取和写入一组单元到数组中更快

MyArray = range("B2:B20000") 

而不是逐个单元格(对于每个...)。

于 2009-08-18T13:52:19.343 回答