优化ClosedXML循环和行删除的性能

时间:2020-05-12 10:57:10

标签: c# optimization closedxml

我正在读取Excel文件并循环浏览各行,删除符合条件的行

using (var wb = new XLWorkbook(path))
{
    var ws = wb.Worksheet(sheet);
    int deleted = 0;
    for (int row_i = 2; row_i <= ws.LastRowUsed().RowNumber(); row_i++)
    {
        ExcelRow row = new ExcelRow(ws.Row(row_i-deleted));
        row.styleCol = header.styleCol;
        K key = keyReader(row);
        if (!writeData(row,dict[key])) deleted++;
    }
    wb.Save();
}

对于具有数千行的文件,即使没有删除,或者必须删除数百行时,代码也非常慢。

2 个答案:

答案 0 :(得分:0)

您必须执行2个重要的优化。 第一行很琐碎,但影响很大:您需要存储最后一行,因为获取该行的函数很耗时间,比您预期的要多。

int lastrow = ws.LastRowUsed().RowNumber();
for (int row_i = 2; row_i <= lastrow; row_i++)

第二个涉及更多点,它与不删除单个范围时的多个(且缓慢的)行/单元格移位(XLShiftDeletedCells.ShiftCellsUp)有关。在这种情况下,我可以建议一种解决方法。请勿在{{1​​}}期间删除单行-请注意,因此您不会递减

writeData

您的循环索引-但暂时添加一列(ExcelRow row = new ExcelRow(ws.Row(row_i)); // no deletion in the loop )以将行标记为“ temp_col”或“ ok”并最终对其进行排序,以便可以删除所有单个范围内的行。

skip

性能测试

无需添加关于第一点的任何内容。第二个是这个答案的原始内容,我可以确认,通过用if (deleted > 0) { int lastcol = ws.LastColumnUsed().ColumnNumber(); var tab = ws.Range(ws.Cell(2, 1), ws.Cell(lastrow, lastcol)); tab.Sort(temp_col); tab = ws.Range(ws.Cell(lastrow - deleted + 1, 1), ws.Cell(lastrow, lastcol)); tab.Delete(XLShiftDeletedCells.ShiftCellsUp); } ws.Column(temp_col).Delete(); 测量经过的时间,观察到的执行时间减少了80%以上。在我的情况下(从200到27秒)。

答案 1 :(得分:0)

首先,请阅读速度说明:https://ericlippert.com/2012/12/17/performance-rant/

关于优化潜力:

瓶颈应该是磁盘。除非您有类似SSD的RAID 0或vsVersion=$(/Applications/Visual\ Studio.app/Contents/MacOS/VisualStudio -h | sed -E -n 's:[^0-9]+([0-9]+[0-9\.]*):\1:p') msbuildVersion=$(msbuild /version | sed -E -n 's:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+):\1:p') monoVersion=$(cat /Library/Frameworks/Mono.framework/Versions/Current/VERSION) xamariniOSVersion=$(cat /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/Version) xamarinAndroidVersion=$(cat /Library/Frameworks/Xamarin.Android.framework/Versions/Current/Version).$(cat /Library/Frameworks/Xamarin.Android.framework/Versions/Current/Version.rev) xamarinFormsVersion=$(sed -E -n 's:.+Xamarin\.Forms[^0-9]+([0-9\.]+).+:\1:p' $PATH_TO_PROJECT_PACKAGES/packages.config) 或这些字典中的详细计算信息,否则CPU不可能成为一个相关因素。因此,最重要的是永远不要两次重复相同的值

如果要消除计算时间,可以对下一列进行一些延迟的后台加载。您应该可以轻松地用枚举器替换直接访问。这样可以将执行时间基本上降低到磁盘速度。

相关问题