【问题标题】:Excel Automation Performance of VB6 client application versus C# client applicationVB6 客户端应用程序与 C# 客户端应用程序的 Excel 自动化性能
【发布时间】:2011-08-05 18:12:02
【问题描述】:

我已投入大量时间将一些旧的 VB6 / *.xla 代码转换为 C# 应用程序,现在我发现自己陷入了一个重大的性能漏洞。从 C# (VS 2010) 自动化 Excel 似乎会对性能产生某种重大影响。我在测试 VB6 应用程序中编写了“精确”代码,并在大约 1-2 秒内运行计算。因为 C# 中的代码需要一分钟。代码的一般流程是这样的……(其中客户端是 VB6 或 C# 应用程序)。

-- 在客户端应用程序的生命周期内只执行一次

  1. 客户端创建并打开 Excel 应用程序

  2. 客户端使 Excel 自动加载计算所需的加载项。

    -- 为执行的每个计算完成

  3. 客户端使 Excel 自动关闭任何现有的 *.xls 文件并打开所需的 *.xls 文件。

  4. 客户端使用 ExcelAppObject.Run("AddIn.xla!GetConfiguration") 从 Excel 调用宏添加以获取在步骤 3 中打开的 *.xls 的配置。

  5. 客户端从 Excel 调用宏,使用 ExcelAppObject.Run("AddIn.xla!LoadInputs", InputsXmlString)

    1. 宏将 InputsXmlString 加载到 MSXML.DOMDocument40 对象中。
    2. 宏将 Application.Calculation = xlCalculationManual(以加快填充多个输入“表”的速度)
    3. 宏设置 Application.EnableEvents = false
    4. 宏循环“输入”工作表上的所有“已配置”输入/表并清除它们(以防传入的 xml 不包含“所有”输入)
    5. 宏循环所有传入的 xml 并加载到“输入”工作表上的适当位置。
  6. 客户端从 Excel 调用宏,使用 ExcelAppObject.Run("AddIn.xla!GetResults", DataXmlString)

    1. 宏将 DataXmlString 加载到 MSXML.DOMDocument40 对象中。
    2. 宏循环“输入”工作表上的所有“配置”数据值并清除它们(以防传入的 xml 不包含“所有”数据或清除之前的计算)
      这与 LoadInputs 不同,因为我们可以进行批量计算,其中每次计算的输入都相同,但每次计算的“参与者数据”显然不同
    3. 宏将 DataXmlString 中的所有数据加载到“输入”工作表上的适当位置
    4. 宏设置 Application.EnableEvents = true
    5. 宏将 Application.Calculation = xlCalculationAutomatic(以确保在所有数据/输入都已加载后进行计算)
    6. 宏循环所有已配置的“结果单元格”并通过 Xml 字符串返回。

如您所见,对于每个计算,我只有三个从客户端到 Excel 的“跨进程”调用(GetConfiguration、LoadInputs 和 GetResults)来尝试最小化已知的“差”性能问题。问题是,当从 VB6 应用程序中调用完全相同的代码时,步骤 4-6 大约需要 2 秒。当客户端应用程序是 C# 应用程序时,4-6 大约需要 70 秒。 所有这 70 秒都发生在第 6 步,当我将计算转回自动时。

相对于旧版 VB6 应用程序,C# 应用程序自动化 Excel 是否存在已知问题和/或是否有任何建议的变通方法,以便我可以保留 C# 代码但以某种方式实现与 VB6 相同的性能?

【问题讨论】:

  • 尝试在发布模式下构建您的应用程序并在 Visual Studio 之外运行它。
  • 我们是/已经内置发布。然后开始调试和发现问题,我们现在在 LINQPad 中使用“更简单”更直接的脚本而不是我们的整个“代理”代码/框架进行测试。
  • 所以你试过在不附加任何调试器的情况下运行它?

标签: c# performance excel vb6 automation


【解决方案1】:

使用 C# 通过 COM Interop 与 Excel 进行交互,从性能的角度来看,通常是极差的: 我建议如果您想继续使用 C#,请查看 Excel DNA 或 Addin Express,这两者都使您能够使用 C# 中更快的 XLL 接口。 见http://fastexcel.wordpress.com/2011/07/07/excel-udf-technology-choices-snakes-ladders-with-vba-vb6-net-c-com-xll-interop/ 感谢我对当前与 Excel 交互的可用技术选择的简要评估。

C# 的主要性能瓶颈通常是将数据从 Excel 传输到 C#:每次数据传输调用都会产生很大的开销,因此使用数组传输大块数据通常要快得多。

【讨论】:

  • 认为您可能错过了我的主要问题。我已将 C# 到 Excel 的调用最小化为“三”。但是,当调用客户端 C# 时,将 Application.Calculation = xlCalculationAutomatic(在 Excel/VBA 中)的简单操作与客户端是 VB6 时相比,会导致性能上的巨大差异。我知道从客户端到 Excel 的多次调用(无论是 VB6 还是 C#)都是不好的,这就是为什么我把它降到最低限度。
  • Charles - 我阅读了您的产品。我不确定它是否/如何帮助我们的计算,但是我的公司不是电子表格的“所有者”。其他“开发人员”将它们提供给我们,因此我们需要让他们为不同客户更新所有电子表格。因此,我再次阅读,试图准确掌握您的产品可能提供的内容,并查看这些好处是否值得进行所有转换所需的努力。
  • Terry:我很困惑——你的实际计算时间是否增加了(第 5 步,在这种情况下你使用的是 c# UDF 吗?)或读取计算结果所花费的时间(第 6 步,循环结果单元格听起来像是一个接一个地读取它们)?
  • 不使用任何 C# UDF。 C# 调用三个 vba UDF(GetConfiguration、LoadInputs、GetResults)。在 vba UDF 内部是发生任何/所有循环和单元格/范围访问的地方。基本上,C# 打包一个 Xml 指令字符串并发送到 vba UDF,它反过来返回一个 Xml 字符串“结果”。但是当从 C# 调用时,udf (Application.Calculation = xlCalculationAutomatic) 中的一行的行为会有所不同。当客户端是 VB6 时,它是即时的。当客户端是 C# 时,需要 60 秒。超越令人沮丧和莫名其妙。
  • 现在我更加困惑了——我们必须使用不同的术语。 UDF 是用某种语言(VBA、c# ...)编写的函数,可从工作表单元格调用。 Application.Calculate 在 UDF 中无效,因为 UDF 是从计算中调用的。
猜你喜欢
  • 1970-01-01
  • 2010-09-18
  • 2011-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-05
相关资源
最近更新 更多