VB.NET / COM服务器代码方式比Excel VBA代码慢 [英] VB.NET/COM Server code way slower than Excel VBA code

查看:137
本文介绍了VB.NET / COM服务器代码方式比Excel VBA代码慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景



我有一个客户需要Excel VBA代码才能将公式值移动到VB.NET。他从事提供财务分析的业务,在这种情况下作为Excel加载项提供。我已经将VBA翻译成在单独的DLL中运行的VB.NET代码。 DLL被编译为COM服务器,因为,Excel,可调用的.NET UDF必须是。到目前为止,这样好:Excel单元格有= foo(Range1,Range2,...),调用VB.NET Com Server的UDF,并且单元格获得一个与VBA代码值匹配的值。



问题



VB.NET代码的运行速度较慢。我可以拉伸一系列基于VBA的公式,并得到即时计算。我可以拉伸相当范围的基于VB.NET的公式,计算需要5-10秒。



我有以下几种可能性:


  1. VBA的原生编译因为没有开关而更快

  2. 每个UDF调用可以加载和卸载DLL


  3. 从DLL中调用Excel WorksheetFunction方法很昂贵
  4. $ b $ b

我不认为(2)是真的,因为我把调用附加到共享新,公共新和最终化函数中的文件,我得到的是:

 共享子新
公共子新
Finalize



当我打开电子表格,反复展开公式范围,并关闭电子表格。



我不认为(3)是真的,因为文件写作表明Application对象只创建一次。



问题



如何知道需要多少时间?如何在这个环境中配置文件?有没有明显的增强?



在最后一个类别中,我试图减少一个Application对象的创建数量(用于WorkSheetFunction调用) / p>

 < Guid(1ECB17BB-444F-4a26-BC3B-B1D6F07D670E)& _ 
< ClassInterface(ClassInterfaceType.AutoDual)> _
< ComVisible(True)> _
< ProgId(Library.Class)> _
公共类MyClass
私有共享应用程序作为应用程序'非常烦人

strong>采取的方法



我试图通过重写我自己来减少对Excel数学函数的依赖。我替换了Min,Max,Average,Stdev,Small,Percentile,Skew,Kurtosis等等。我的UDF代码调用到Excel少得多。不可避免的调用似乎将一个Range作为参数,并将其转换为.NET内部使用的数组。

解决方案


DLL被编译为COM服务器
,因为,Excel可调用的.NET
UDF必须是


一个show-stopper的位,如果是真的,我同意。但是,当然,这是不是真的,为什么我会开始这样的方式...



您可以在C ++中针对Excel SDK编写UDF,交付他们作为XLL,一件事。这是银行定量分析师的常见做法;



另一个不太痛苦的选择,我最近才碰到过,是< a href =http://groups.google.com/group/exceldna/web/introducing-exceldna---dotnet-for-applications =nofollow noreferrer> ExcelDNA ,AFAICT提供令人讨厌的SDK / XLL位与一个方法来挂接你的.NET DLL。它足够酷,它甚至允许你加载源代码,而不是建立一个单独的DLL,这是伟大的原型(它利用的事实,CLR实际上包含编译器)。我不知道性能:我没有尝试基准,但它似乎解决了COM互操作问题,这是众所周知的ghastly。



除此之外,我只能批准其他建议:尽可能少地引用您的工作簿,其内容和Excel应用程序。每次通话费用。


Background

I have a client who needs Excel VBA code that produces formula values moved to VB.NET. He is in the business of providing financial analytics, in this case delivered as an Excel add-in. I have translated the VBA into VB.NET code that runs in a separate DLL. The DLL is compiled as a COM Server because, well, Excel-callable .NET UDFs have to be. So far, so good: Excel cells have "=foo(Range1, Range2, ...)", the VB.NET Com Server's UDF is called, and the cell obtains a value that matches the VBA code's value.

The problem

The VB.NET code is way slower. I can stretch a range of VBA-based formulas and get instantaneous calculation. I can stretch a comparable range of VB.NET-based formulas and the calculation takes 5-10 seconds. It is visibly slower and unacceptable to the client.

There are a few possibilities that occur to me:

  1. native compilation of VBA is faster because of the absence of a switch
  2. the DLL may be loaded and unloaded for each UDF call
  3. the DLL calls Excel WorksheetFunction methods and requires an Application object, and creating the Application object is expensive
  4. calling an Excel WorksheetFunction method from the DLL is expensive

I don't think that (2) is true because I put calls to append to a file in the Shared New, the Public New, and Finalize functions, and all I get are:

Shared Sub New
Public Sub New
Finalize

when I open the spreadsheet, repeatedly stretch a formula range, and close the spreadsheet.

I don't think (3) is true because the file writing shows that the Application object is created only once.

The question

How do I figure out what is taking the time? How to profile in this environment? Are there obvious enhancements?

In the last category, I have tried to reduce the number of creations of an Application object (used for WorkSheetFunction calls) by making it Shared:

<Guid("1ECB17BB-444F-4a26-BC3B-B1D6F07D670E")> _
<ClassInterface(ClassInterfaceType.AutoDual)> _
<ComVisible(True)> _
<ProgId("Library.Class")> _
Public Class MyClass
    Private Shared Appp As Application ' Very annoying

Approaches taken

I've tried to reduce the dependence on Excel mathematical functions by rewriting my own. I've replaced Min, Max, Average, Stdev, Small, Percentile, Skew, Kurtosis, and a few more. My UDF code calls out to Excel much less. The unavoidable call seems to be taking a Range as an argument and converting that to a .NET Array for internal use.

解决方案

The DLL is compiled as a COM Server because, well, Excel-callable .NET UDFs have to be

A bit of a show-stopper if true, I agree. But of course, it isn't true at all, why else would I have started that way...

You can write your UDFs in C++ against the Excel SDK and deliver them as an XLL, for one thing. It's a common practice among quantitative analysts in banks; in fact they seem to enjoy it, which says a lot about them as a group.

Another, less painful option, that I've only recently come across, is ExcelDNA, which, AFAICT, provides the nasty SDK/XLL bit with a way to hook up your .NET DLLs. It's sufficiently cool that it even lets you load source code, rather than building a separate DLL, which is great for prototyping (it makes use of the fact that the CLR actually contains the compiler). I don't know about performance: I haven't attempted to benchmark it, but it does seem to get around the COM Interop issue, which is well-known to be ghastly.

Beyond that, I can only endorse other recommendations: reference your workbook, its content and the Excel application as little as possible. Every call costs.

这篇关于VB.NET / COM服务器代码方式比Excel VBA代码慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆