Excel Interop - 效率和性能

时间:2008-12-10 15:03:46

标签: c# excel performance interop vsto

我想知道如何提高Excel自动化的性能,因为如果您在工作表中进行了很多工作,它可能会非常慢......

以下是我发现的一些事情:

  • ExcelApp.ScreenUpdating = false - 关闭重新绘制屏幕

  • ExcelApp.Calculation = Excel.XlCalculation.xlCalculationManual - 关闭计算引擎,以便Excel在单元格值更改时不会自动重新计算(在完成后重新打开)

  • 减少对Worksheet.Cells.Item(row, col)Worksheet.Range的调用 - 我不得不轮询数百个单元格以找到我需要的单元格。实现一些单元格位置的缓存,将执行时间从大约40秒减少到大约5秒。

什么样的互操作会对性能造成严重影响,应该避免?你还能做些什么来避免不必要的处理?

7 个答案:

答案 0 :(得分:47)

当使用C#或VB.Net获取或设置范围时,找出范围的总大小,然后得到一个大的二维对象数组......

//get values
object[,] objectArray = shtName.get_Range("A1:Z100").Value2;
iFace = Convert.ToInt32(objectArray[1,1]);

//set values
object[,] objectArray = new object[3,1] {{"A"}{"B"}{"C"}};
rngName.Value2 = objectArray;

请注意,重要的是您知道Excel存储的数据类型(文本或数字),因为当您从对象数组转换回来时,它不会自动为您执行此操作。如果您无法事先确定数据类型,则在必要时添加测试以验证数据。

答案 1 :(得分:12)

这适用于任何想知道从db结果集填充Excel工作表的最佳方法。这并不是一个完整的列表,但它列出了一些选项。

尝试使用旧的Pentium 4 3GHz盒子上的155列和4200条记录填充excel表时的一些性能数据,包括数据检索时间从最慢到最快的顺序不超过10秒,如下所示...... / p>

  1. 一次一个单元格 - 不到11分钟

  2. 通过转换为html +将html保存到磁盘来填充数据集+将html加载到excel并将工作表保存为xls / xlsx - 5分钟

  3. 一次一列 - 4分钟

  4. 在SQL 2005中使用已弃用的sp_makewebtask过程来创建HTML文件 - 9秒+然后在excel中加载html文件并另存为XLS / XLSX - 大约2分钟。 < / p>

  5. 将.Net数据集转换为ADO RecordSet并使用WorkSheet.Range []。CopyFromRecordset函数填充excel - 45秒!

  6. 我最终使用了选项5.希望这会有所帮助。

答案 2 :(得分:5)

尽可能使用excels内置功能,例如:不使用整列搜索给定字符串,而是使用Ctrl-F中GUI中提供的find命令:

Set Found = Cells.Find(What:=SearchString, LookIn:=xlValues, _
    SearchOrder:=xlByRows, SearchDirection:=xlNext, _
    MatchCase:=False, SearchFormat:=False)

If Not Found Is Nothing Then
    Found.Activate
    (...)
EndIf

如果要对某些列表进行排序,请使用excel sort命令,不要在VBA中手动执行:

Selection.Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlGuess, _
    OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
    DataOption1:=xlSortNormal

答案 3 :(得分:5)

如果您正在轮询许多单元格的值,您可以一次性获取存储在变体数组中的范围内的所有单元格值:

Dim CellVals() as Variant
CellVals = Range("A1:B1000").Value

这里有一个权衡,就你所获得的范围大小而言。我想如果你需要一千个或更多的单元格值,这可能比循环遍历不同的单元格并轮询值更快。

答案 4 :(得分:2)

性能还很大程度上取决于您如何自动化Excel。 VBA比COM自动化比.NET自动化更快。通常早期(编译时)绑定也比后期绑定快。

如果您遇到严重的性能问题,可以考虑将代码的关键部分移动到VBA模块,并从COM / .NET自动化代码中调用该代码。

如果您使用.NET,您还应该使用Microsoft提供的优化主互操作程序集,而不是使用自定义构建的互操作程序集。

答案 5 :(得分:1)

正如匿名类型所说:读/写大范围块对性能非常重要。

如果COM-Interop开销仍然太大,您可能希望切换到使用XLL接口,这是最快的Excel接口。

虽然XLL接口主要用于C ++用户,但XL DNA和Addin Express都提供.NET到XLL桥接功能,这比COM-Interop快得多。

答案 6 :(得分:0)

你可以在VBA中做的另一件大事是使用Option Explicit并尽可能避免使用Variants。变体在VBA中不是100%可以避免的,但是它们使得解释器在运行时做更多工作并浪费内存。

当我在Excel中使用VBA开始时,我发现这篇文章非常有用 http://www.ozgrid.com/VBA/SpeedingUpVBACode.htm

这本书

http://www.amazon.com/VB-VBA-Nutshell-Language-OReilly/dp/1565923588

相似
 app.ScreenUpdates = false //and
 app.Calculation = xlCalculationManual

你也可以设置

 app.EnableEvents = false //Prevent Excel events
 app.Interactive = false  //Prevent user clicks and keystrokes

虽然它们似乎没有前两个那么大。

与将Range值设置为数组类似,如果使用的数据主要是列的每一行中具有相同公式的表,则可以对公式使用R1C1公式表示法,并将整个列设置为等于公式用于在一次调用中设置整个事物的字符串。

app.ReferenceStyle = xlR1C1
app.ActiveSheet.Columns(2) = "=SUBSTITUTE(C[-1],"foo","bar")"

此外,使用ExcelDNA&amp; amp;创建XLL加载项.NET(或C中的硬盘方式)也是让UDF在多个线程上运行的唯一方法。 (请参阅Excel DNA的ExcelFunction属性的IsThreadSafe属性。)

在我完全转换到Excel DNA之前,我还尝试在.NET中创建COM可见库以在VBA项目中引用。重文本处理比VBA快一点,就像使用包装的.NET List类而不是VBA的Collection一样,但Excel DNA更好。