优化数据处理方法的性能

本文关键字:性能 方法 数据处理 优化 | 更新日期: 2023-09-27 18:02:45

我使用以下代码从.txt文件中获取一些数据(以XML格式-格式不佳),然后在进行一些处理后使用EPPlus将其写入.xlsxStreamElements基本上是改性的XmlReader。我的问题是关于性能的,我已经做了一些改变,但不知道我还能做些什么。我将把它用于大型数据集,所以我正在尝试修改,使其尽可能高效和快速。任何帮助将不胜感激!

我尝试使用p.SaveAs()来做excel写作,但它并没有真正看到性能差异。有没有更好更快的写作方法?欢迎提出任何建议。

using (ExcelPackage p = new ExcelPackage())
    {
    ExcelWorksheet ws = p.Workbook.Worksheets[1];
    ws.Name = "data1";
    int rowIndex = 1; int colIndex = 1;
      foreach (var element in StreamElements(pa, "XML"))
      {
         var values = element.DescendantNodes().OfType<XText>()
         .Select(v => Regex.Replace(v.Value, "''s+", " "));
         string[] data = string.Join(",", values).Split(',');
         data[2] = toDateTime(data[2]);
         for (int i = 0; i < data.Count(); i++)
         {
           if (rowIndex < 1000000) 
           { 
           var cell1 = ws.Cells[rowIndex, colIndex];
           cell1.Value = data[i];
           colIndex++;
           }
         }
         rowIndex++;
      }
    }
    ws.Cells[ws.Dimension.Address].AutoFitColumns();
    Byte[] bin = p.GetAsByteArray();
    using (FileStream fs = File.OpenWrite("C:''test.xlsx"))
    {
      fs.Write(bin, 0, bin.Length);
    }
  }
}

目前,对于它进行处理,然后将100万行写入Excel工作表,大约需要30-35分钟。

优化数据处理方法的性能

我以前遇到过这个问题,当你逐个修改工作表单元格时,excel有一个巨大的开销。

解决这个问题的方法是创建一个对象数组,并使用WriteRange功能填充工作表。

using(ExcelPackage p = new ExcelPackage()) {
    ExcelWorksheet ws = p.Workbook.Worksheets[1];
    ws.Name = "data1";
    //Starting cell
    int startRow = 1;
    int startCol = 1;
    //Needed for 2D object array later on
    int maxColCount = 0;
    int maxRowCount = 0;
    //Queue data
    Queue<string[]> dataQueue = new Queue<string[]>();
    //Tried not to touch this part
    foreach(var element in StreamElements(pa, "XML")) {
        var values = element.DescendantNodes().OfType<XText>()
            .Select(v = > Regex.Replace(v.Value, "''s+", " "));
        //Removed unnecessary split and join, use ToArray instead
        string[] eData = values.ToArray();
        eData[2] = toDateTime(eData[2]);
        //Push the data to queue and increment counters (if needed)
        dataQueue.Enqueue(eData);
        if(eData.Length > maxColCount)
            maxColCount = eData.Length;
        maxRowCount++;
    }
    //We now have the dimensions needed for our object array
    object[,] excelArr = new object[maxRowCount, maxColCount];
    //Dequeue data from Queue and populate object matrix
    int i = 0;
    while(dataQueue.Count > 0){
        string[] eData = dataQueue.Dequeue();
        for(int j = 0; j < eData.Length; j++){
            excelArr[i, j] = eData[j];
        }
        i++;
    }
    //Write data to range
    Excel.Range c1 = (Excel.Range)wsh.Cells[startRow, startCol];
    Excel.Range c2 = (Excel.Range)wsh.Cells[startRow + maxRowCount - 1, maxColCount];
    Excel.Range range = worksheet.Range[c1, c2];
    range.Value2 = excelArr;
    //Tried not to touch this stuff
    ws.Cells[ws.Dimension.Address].AutoFitColumns();
    Byte[] bin = p.GetAsByteArray();
    using(FileStream fs = File.OpenWrite("C:''test.xlsx")) {
        fs.Write(bin, 0, bin.Length);
    }
}

我没有尝试编译这段代码,所以请仔细检查所使用的索引;并检查任何小的语法错误。

考虑性能的几个额外指针:

  • 尝试并行对象数组的填充,因为它主要是基于索引的(可能有一个带有索引跟踪器Dictionary<int, string[]>的字典),并在那里查找以更快地填充对象数组。你可能不得不用空间换取时间。
  • 看看你是否能够硬编码列和行计数,或者快速计算出来。在我的代码修复中,我设置了计数器来动态计算最大行数和列数;我不建议将其作为永久解决方案。
  • AutoFitColumns是非常昂贵的,特别是如果你处理超过一百万行