C# Excel互操作-效率和性能
我想知道我能做些什么来提高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的调用--我必须轮询
——关闭屏幕重画ExcelApp.ScreenUpdate=false
——关闭计算引擎,使Excel不会在单元格值更改时自动重新计算(完成后重新打开)ExcelApp.Calculation=Excel.XlCalculation.xlCalculationManual
- 减少对
和工作表.Cells.Item(row,col)
的调用--我必须轮询数百个单元格才能找到所需的单元格。实现一些单元位置缓存,将执行时间从约40秒减少到约5秒工作表.Range
什么样的互操作调用会严重影响性能,应该避免?您还可以做些什么来避免不必要的处理呢?性能也在很大程度上取决于您如何自动化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
如果要对某些列表进行排序,请使用excelsort
命令,不要在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秒)的一些性能数据如下所示
我最终使用了选项5。希望这有帮助。正如匿名类型所说:读取/写入大范围块对性能非常重要 在COM互操作开销仍然过大的情况下,您可能希望切换到使用XLL接口,这是最快的Excel接口
这本书呢 近似
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