C# 优化数据处理方法的性能

C# 优化数据处理方法的性能,c#,excel,epplus,C#,Excel,Epplus,我使用以下代码从.txt文件中获取一些数据(类似XML的格式-格式不正确),然后在执行一些处理后使用EPPlus将其写入.xlsxStreamElements基本上是一个经过修改的XmlReader。我的问题是关于性能,我做了一些改变,但不知道还能做些什么。我将对大型数据集使用它,所以我尝试修改它,使其尽可能高效和快速。任何帮助都将不胜感激 我尝试使用p.SaveAs()编写excel,但没有发现性能上的差异。有更好更快的写作方法吗?欢迎提出任何建议 using (ExcelPackage p

我使用以下代码从
.txt
文件中获取一些数据(类似XML的格式-格式不正确),然后在执行一些处理后使用EPPlus将其写入
.xlsx
StreamElements
基本上是一个经过修改的
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);
    }

  }
}
使用(ExcelPackage p=new ExcelPackage())
{
Excel工作表ws=p.Workbook.Worksheets[1];
ws.Name=“data1”;
int rowIndex=1;int colIndex=1;
foreach(streamelement(pa,“XML”)中的var元素)
{
var values=element.degenantnodes().OfType()的
。选择(v=>Regex.Replace(v.Value,“\\s+”,”);
string[]data=string.Join(“,”值).Split(“,”);
数据[2]=toDateTime(数据[2]);
对于(int i=0;i

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

我以前遇到过这个问题,Excel在逐个修改工作表单元格时会产生巨大的开销

解决方案是创建一个对象数组,并使用该功能填充工作表

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);
    }
}
使用(ExcelPackage p=new ExcelPackage()){
Excel工作表ws=p.Workbook.Worksheets[1];
ws.Name=“data1”;
//起始电池
int startRow=1;
int startCol=1;
//以后需要2D对象数组
int maxColCount=0;
int maxRowCount=0;
//队列数据
队列数据队列=新队列();
//尽量不要碰这部分
foreach(streamelement(pa,“XML”)中的var元素){
var values=element.degenantnodes().OfType()的
。选择(v=>Regex.Replace(v.Value,“\\s+”,”);
//删除了不必要的拆分和联接,请改用ToArray
字符串[]eData=values.ToArray();
eData[2]=当前时间(eData[2]);
//将数据推送到队列和增量计数器(如果需要)
dataQueue.Enqueue(eData);
如果(eData.Length>maxColCount)
maxColCount=数据长度;
maxRowCount++;
}
//现在我们有了对象数组所需的维度
object[,]excelArr=新对象[maxRowCount,maxColCount];
//从队列中取出数据并填充对象矩阵
int i=0;
而(dataQueue.Count>0){
字符串[]eData=dataQueue.Dequeue();
对于(int j=0;j
我没有尝试编译这段代码,所以仔细检查使用的索引;并检查是否存在任何小的语法错误

为性能考虑的额外指针:

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

运行探查器,哪些行占用的时间最多。这并不是说它会提高性能,而是说所有写出的代码都可以重写为
文件。writealBytes(@“c:\test.xlsx”,p.GetAsByteArray())。你有没有分析过这个?在写作或处理过程中,在哪里花费的时间最多?考虑使用编译的正则表达式:这条线的意义是什么?代码>字符串.Join(“,”值).Split(“,”)?我一点也不确定(因此将其作为注释编写),但如果实际使用仅向前的读取器而不是
元素,则可能会获得更好的速度和内存利用率。后代节点…
,然后是
string[]data=string.Join(“,”,values).Split(“,”)
应该能够在创建
值时直接完成,并且不需要
数据
数组。。。再说一次,如果我是对的,没有任何线索,只是脑海中浮现的想法,我希望能有所帮助…@朗拜尔同意,这句话看起来不对。。。我很久以前写过这个
string.Join(“,”,values.Split(“,”)
。。但是,获取包含
var值的字符串数组的另一种方法是什么呢?
values.ToArray()
,或者您可以将其附加到
的末尾。选择(…)
语句并将数组存储在
values
变量中。我尝试了这个方法,但是