使用EPPlus和Spreadsheet Gear读取/写入许多文件时的性能差异

时间:2012-11-22 11:43:20

标签: performance excel epplus spreadsheetgear

我在EPPlus和Spreadsheet Gear之间做了一个简单的性能测试,看看是否有任何重大差异可以证明购买Spreadsheet Gear。

我不是任何一个应用程序的专家,因此测试可能不是最有效的方式。

测试执行以下操作: 1.打开包含1000行和3列的现有Excel文件。将三个值保存到保存到List<>中的实体中。 2.打开一个新的Excel对象 3.使用每列的标题创建标题行(粗体)。 4.回写1000个实体。 5.保存新的Excelfile。

如果我在EPPlus获胜后进行此测试(大约是EPPlus = 280ms,SG = 500ms)。如果我连续10次运行测试(一个for循环打开,复制,保存10个单独的时间)Spreadsheet Gear更快(相当于每个文件:EPPlus = 165ms,SG = 95ms)。对于20次测试,大约时间是EPPlus = 160ms / file和SG = 60ms / file。

似乎(至少在某种程度上)Spreadsheet Gears越多越快,我创建的文件越多。 任何人都可以解释为什么EPPlus在运行连续测试时速度较慢?我可以对代码进行更改以更改此内容吗?

EPPlus测试功能:

var timer = new Stopwatch();
  timer.Start();
  var data = new List<Item>();
  using (var excelIn = new ExcelPackage(new FileInfo(folder + fileIn)))
  {
    var sheet = excelIn.Workbook.Worksheets[1];
    var row = 2;
    while (sheet.Cells[row, 1].Value != null)
    {
      data.Add(new Item()
        {
          Id = int.Parse(sheet.Cells[row, 1].Text),
          Title =  sheet.Cells[row, 2].Text,
          Value = int.Parse(sheet.Cells[row, 3].Text)
        });

      row++;
    }
  }

  using (var excelOut = new ExcelPackage())
  {
    var sheet = excelOut.Workbook.Worksheets.Add("Out");
    sheet.Cells.LoadFromCollection(data);
    sheet.InsertRow(1, 1);
    sheet.Cells[1, 1, 1, 3].Style.Font.Bold = true;
    sheet.Cells[1, 1].Value = "Id";
    sheet.Cells[1, 2].Value = "Title";
    sheet.Cells[1, 3].Value = "Value";

    excelOut.SaveAs(new FileInfo(folder + "EPPlus_" + Guid.NewGuid() + ".xlsx"));
  }

  timer.Stop();
  return timer.ElapsedMilliseconds;

Spreadsheet Gear:

var timer = new Stopwatch();
  timer.Start();

  var data = new List<Item>();
  var excelIn = Factory.GetWorkbook(folder + fileIn);
  var sheetIn = excelIn.Worksheets[0];
  var rowIn = 1;
  while (sheetIn.Cells[rowIn, 0].Value != null)
  {
    data.Add(new Item()
    {
      Id = int.Parse(sheetIn.Cells[rowIn, 0].Text),
      Title = sheetIn.Cells[rowIn, 1].Text,
      Value = int.Parse(sheetIn.Cells[rowIn, 2].Text)
    });

    rowIn++;
  }
  excelIn.Close();

  var excelOut = Factory.GetWorkbook();
  var sheetOut = excelOut.Worksheets.Add();
  sheetOut.Name = "Out";
  var rowOut = 0;
  sheetOut.Cells[rowOut, 0, rowOut, 2].Font.Bold = true;
  sheetOut.Cells[rowOut, 0].Value = "Id";
  sheetOut.Cells[rowOut, 1].Value = "Title";
  sheetOut.Cells[rowOut++, 2].Value = "Value";

  foreach (var item in data)
  {
    sheetOut.Cells[rowOut, 0].Value = item.Id;
    sheetOut.Cells[rowOut, 1].Value = item.Title;
    sheetOut.Cells[rowOut++, 2].Value = item.Value;
  }

  excelOut.SaveAs(folder + "SpreadsheetGear_" + Guid.NewGuid() + ".xlsx", FileFormat.OpenXMLWorkbook);
  excelOut.Close();

  timer.Stop();
  return timer.ElapsedMilliseconds;

主要功能

var runs = 1;
  var testerG = new TestSpreadsheetGear();
  var testerE = new TestEpPlus();
  var msE = 0.0;
  var msG = 0.0;
  var i = 0;
  for (i = 0; i < runs; ++i)
  {
    msG += new TestSpreadsheetGear().Run(folder, originalFile);
  }

  for(i = 0; i < runs; ++i)
  {
    msE += new TestEpPlus().Run(folder, originalFile);
  }

  Console.WriteLine("Spreadsheet time: " + msG + ". Per file: " + msG / runs);
  Console.WriteLine("EP Plus time: " + msE + ". Per file: " + msE / runs);
  Console.ReadKey();

1 个答案:

答案 0 :(得分:2)

我相信您看到的结果的原因是,在第一次运行时,.NET CLR必须JIT代码。由于SpreadsheetGear是一个完整的电子表格引擎(与读/写库相对),JIT还有更多代码 - 因此SpreadsheetGear的首次运行时间比EPPlus要长(我在这里推测但是有很多经验)在过去10年中对.NET代码进行基准测试。)

我没有安装EPPlus,但我确实编写了一个试图做同样事情的测试。使用SpreadsheetGear 2012由于我没有您的开始工作簿,我首先构建工作簿。然后,我使用了更优化的SpreadsheetGear API。我第一次运行时,SpreadsheetGear 2012获得141毫秒。第一次运行后,在运行Win7 x86的超频Core i7-980x和没有调试器的发布版本运行中,每次运行得到9或10毫秒。

我已粘贴下面的代码(只需将其粘贴到.NET 4.0 C#控制台应用程序中)。

我还有一个想法是,这是一个非常小的测试用例。要真正了解SpreadsheetGear 2012的性能,请尝试使用100,000行甚至100万行。

免责声明:我拥有SpreadsheetGear LLC

using System;
using System.Collections.Generic;
using System.Diagnostics;
using SpreadsheetGear;

namespace SGvsEPPlus
{
    class Program
    {
        internal struct Item
        {
            internal Item(int id, string title, int value)
            {
                Id = id;
                Title = title;
                Value = value;
            }

            internal int Id;
            internal string Title;
            internal int Value;
        }

        static void Test(int rows)
        {
            string filename = @"C:\tmp\MyWorkbook.xlsx";
            Console.Write("Test({0})...", rows);
            var timer = new Stopwatch();
            // Create workbook since we don't have poster's original workbook.
            timer.Restart();
            var workbook = Factory.GetWorkbook();
            var values = (SpreadsheetGear.Advanced.Cells.IValues)workbook.Worksheets[0];
            for (int row = 1; row <= rows; row++)
            {
                values.SetNumber(row, 0, row);
                values.SetText(row, 1, "Title " + row);
                values.SetNumber(row, 2, row * 10);
            }
            Console.Write("Create workbook={0:0}...", timer.Elapsed.TotalMilliseconds);
            // Save workbook
            timer.Restart();
            workbook.SaveAs(filename, FileFormat.OpenXMLWorkbook);
            Console.Write("Save workbook={0:0}...", timer.Elapsed.TotalMilliseconds);
            // Track total time of original test.
            var totalTimer = Stopwatch.StartNew();
            // Open workbook
            timer.Restart();
            var excelIn = Factory.GetWorkbook(filename);
            Console.Write("Open excelIn={0:0}...", timer.Elapsed.TotalMilliseconds);
            // Copy workbook to list
            timer.Restart();
            var sheetIn = excelIn.Worksheets[0];
            var valuesIn = (SpreadsheetGear.Advanced.Cells.IValues)sheetIn;
            var rowIn = 1;
            var data = new List<Item>(rows);
            while (valuesIn[rowIn, 0] != null)
            {
                data.Add(new Item(
                    (int)valuesIn[rowIn, 0].Number,
                    valuesIn[rowIn, 1].Text,
                    (int)valuesIn[rowIn, 2].Number));
                rowIn++;
            }
            excelIn.Close(); // Not necessary but left for consistency.
            Console.Write("excelIn->data={0:0}...", timer.Elapsed.TotalMilliseconds);
            timer.Restart();
            var excelOut = Factory.GetWorkbook();
            var sheetOut = excelOut.Worksheets[0];
            var valuesOut = (SpreadsheetGear.Advanced.Cells.IValues)sheetOut;
            sheetOut.Name = "Out";
            var rowOut = 0;
            sheetOut.Cells[rowOut, 0, rowOut, 2].Font.Bold = true;
            sheetOut.Cells[rowOut, 0].Value = "Id";
            sheetOut.Cells[rowOut, 1].Value = "Title";
            sheetOut.Cells[rowOut++, 2].Value = "Value";
            foreach (var item in data)
            {
                valuesOut.SetNumber(rowOut, 0, item.Id);
                valuesOut.SetText(rowOut, 1, item.Title);
                valuesOut.SetNumber(rowOut, 2, item.Value);
                rowOut++;
            }
            Console.Write("data->excelOut={0:0}...", timer.Elapsed.TotalMilliseconds);
            timer.Restart();
            excelOut.SaveAs(@"C:\tmp\SpreadsheetGear_" + Guid.NewGuid() + ".xlsx", FileFormat.OpenXMLWorkbook);
            excelOut.Close(); // Again - not necessary.
            Console.WriteLine("Save excelOut={0:0}...", timer.Elapsed.TotalMilliseconds);
            Console.WriteLine("    Total={0:0}", totalTimer.Elapsed.TotalMilliseconds);
        }
        static void Main(string[] args)
        {
            // Do it three times with 1000 rows. Note that the first
            // time takes longer because code must be JITted.
            Test(1000);
            Test(1000);
            Test(1000);
        }
    }
}