C# Excel互操作-效率和性能

C# Excel互操作-效率和性能,c#,excel,performance,interop,vsto,C#,Excel,Performance,Interop,Vsto,我想知道我能做些什么来提高Excel自动化的性能,因为如果您在工作表中有很多事情要做,那么它可能会非常慢 以下是我自己发现的一些: ExcelApp.ScreenUpdate=false——关闭屏幕重画 ExcelApp.Calculation=Excel.XlCalculation.xlCalculationManual——关闭计算引擎,使Excel不会在单元格值更改时自动重新计算(完成后重新打开) 减少对工作表.Cells.Item(row,col)和工作表.Range的调用--我必须轮询

我想知道我能做些什么来提高Excel自动化的性能,因为如果您在工作表中有很多事情要做,那么它可能会非常慢

以下是我自己发现的一些:

  • ExcelApp.ScreenUpdate=false
    ——关闭屏幕重画

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

  • 减少对
    工作表.Cells.Item(row,col)
    工作表.Range
    的调用--我必须轮询数百个单元格才能找到所需的单元格。实现一些单元位置缓存,将执行时间从约40秒减少到约5秒


什么样的互操作调用会严重影响性能,应该避免?您还可以做些什么来避免不必要的处理呢?

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

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


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

尽可能使用Excel内置功能,例如:不要在整列中搜索给定字符串,而是通过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

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

Dim CellVals() as Variant
CellVals = Range("A1:B1000").Value
这里有一个折衷的办法,就是你得到的价值范围的大小。我猜如果你需要一千个或更多的单元格值,这可能比在不同的单元格中循环并轮询值要快。

当使用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存储的数据类型(文本或数字)很重要,因为当您从对象数组转换回该类型时,它不会自动为您执行此操作。如果您事先无法确定数据类型,请在必要时添加测试以验证数据。

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

在旧的奔腾4 3GHz设备上,试图填充包含155列和4200条记录的excel工作表时,包括数据检索时间(从最慢到最快,从不超过10秒)的一些性能数据如下所示

  • 一次一个细胞——不到11分钟

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

  • 一次一列-4分钟

  • 使用SQL 2005中不推荐使用的sp_makewebtask过程创建HTML文件-9秒以上,然后在excel中加载HTML文件并保存为XLS/XLSX-大约2分钟

  • 将.Net数据集转换为ADO记录集,并使用工作表.Range[].CopyFromRecordset函数填充excel-45秒


  • 我最终使用了选项5。希望这有帮助。

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

    在COM互操作开销仍然过大的情况下,您可能希望切换到使用XLL接口,这是最快的Excel接口


    虽然XLL接口主要是针对C++用户的,但XL DIN和AddExpress都提供.NET到XLL桥的能力,这比COM互操作速度快得多。

    < P> VBA可以做的另一件大事是使用选项显式,避免可能出现的变体。变量在VBA中不是100%可以避免的,但它们使解释器在运行时做更多的工作并浪费内存

    当我开始在Excel中使用VBA时,我发现这篇文章非常有用。

    这本书呢

    近似

     app.ScreenUpdates = false //and
     app.Calculation = xlCalculationManual
    
    您还可以设置

     app.EnableEvents = false //Prevent Excel events
     app.Interactive = false  //Prevent user clicks and keystrokes
    
    尽管它们似乎没有前两个有那么大的区别

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

    app.ReferenceStyle = xlR1C1
    app.ActiveSheet.Columns(2) = "=SUBSTITUTE(C[-1],"foo","bar")"
    
    此外,使用ExcelDNA和.NET(或C中的硬方法)创建XLL加载项也是让UDF在多个线程上运行的唯一方法。(请参见Excel DNA的ExcelFunction属性的IsThreadSafe属性。)


    在我完全转换到ExcelDNA之前,我还尝试在.NET中创建COM可见库,以便在VBA项目中引用。通过这种方式,繁重的文本处理比VBA快一点,使用包装的.NET列表类而不是VBA的集合也是如此,但Excel DNA更好。

    all true。但是,如果您按照建议,不进行大量的小范围对象调用来设置Value2属性,只需传入一个对象数组或获取一个对象数组,就不需要使用VBA。+1使用Excel互操作时,我也会遇到性能问题,我学到了一些新东西:
    ExcelApp.Calculation=Excel.XlCalculation.xlCalculationManual
    。谢谢!=)感谢您在问题中分享您当前的发现,非常有用。其他一些可能的选项包括使用2D对象阵列的+1。还有
    shtName