From 1826b0b66925e873082e12d3b29ee1d7dc0b9ed6 Mon Sep 17 00:00:00 2001 From: wei Date: Tue, 30 Mar 2021 21:36:27 +0800 Subject: [PATCH] add closedxml epplus openxmlsdk performance test --- benchmarks/MiniExcel.Benchmarks/Config.cs | 43 ++++ .../MiniExcel.Benchmarks.csproj | 2 +- benchmarks/MiniExcel.Benchmarks/Program.cs | 223 ++++++++++++++++-- 3 files changed, 250 insertions(+), 18 deletions(-) create mode 100644 benchmarks/MiniExcel.Benchmarks/Config.cs diff --git a/benchmarks/MiniExcel.Benchmarks/Config.cs b/benchmarks/MiniExcel.Benchmarks/Config.cs new file mode 100644 index 0000000..5b56a41 --- /dev/null +++ b/benchmarks/MiniExcel.Benchmarks/Config.cs @@ -0,0 +1,43 @@ +using BenchmarkDotNet.Columns; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Exporters; +using BenchmarkDotNet.Exporters.Csv; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Loggers; +using BenchmarkDotNet.Order; + +namespace MiniExcelLibs.Benchmarks +{ + public class Config : ManualConfig + { + public const int Iterations = 3; + + public Config() + { + AddLogger(ConsoleLogger.Default); + + AddExporter(CsvExporter.Default); + AddExporter(MarkdownExporter.GitHub); + AddExporter(HtmlExporter.Default); + + var md = MemoryDiagnoser.Default; + AddDiagnoser(md); + AddColumn(TargetMethodColumn.Method); + AddColumn(StatisticColumn.Mean); + AddColumn(StatisticColumn.StdDev); + AddColumn(StatisticColumn.Error); + AddColumn(BaselineRatioColumn.RatioMean); + AddColumnProvider(DefaultColumnProviders.Metrics); + + AddJob(Job.ShortRun + .WithLaunchCount(1) + .WithWarmupCount(2) + .WithUnrollFactor(Iterations) + .WithIterationCount(3) + ); + Orderer = new DefaultOrderer(SummaryOrderPolicy.FastestToSlowest); + Options |= ConfigOptions.JoinSummary; + } + } +} diff --git a/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj b/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj index 4d97544..d804ebf 100644 --- a/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj +++ b/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj @@ -9,7 +9,7 @@ - + diff --git a/benchmarks/MiniExcel.Benchmarks/Program.cs b/benchmarks/MiniExcel.Benchmarks/Program.cs index 026a8c7..268d68d 100644 --- a/benchmarks/MiniExcel.Benchmarks/Program.cs +++ b/benchmarks/MiniExcel.Benchmarks/Program.cs @@ -5,15 +5,12 @@ using System.Diagnostics; using System.IO; using System.Linq; using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Columns; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; -using BenchmarkDotNet.Exporters; -using BenchmarkDotNet.Exporters.Csv; -using BenchmarkDotNet.Jobs; -using BenchmarkDotNet.Loggers; +using BenchmarkDotNet.Order; using BenchmarkDotNet.Running; using ClosedXML.Excel; +using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Spreadsheet; using ExcelDataReader; @@ -27,9 +24,11 @@ namespace MiniExcelLibs.Benchmarks static void Main(string[] args) { #if !DEBUG - var summary = BenchmarkRunner.Run(); + //new BenchmarkSwitcher(typeof(Program).Assembly).Run(args, new Config()); + BenchmarkRunner.Run(); #else - BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, new DebugInProcessConfig()); + //BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, new DebugInProcessConfig()); + new XlsxBenchmark().ClosedXml_Query_Test(); #endif Console.Read(); } @@ -37,19 +36,25 @@ namespace MiniExcelLibs.Benchmarks [BenchmarkCategory("Framework")] [MemoryDiagnoser] - [SimpleJob(launchCount: 3, warmupCount: 3, targetCount: 3,invocationCount:3,baseline:false)] + [SimpleJob(launchCount: 1, warmupCount: 1, targetCount: 1,invocationCount:1,baseline:false)] + [Orderer(SummaryOrderPolicy.FastestToSlowest)] public abstract class BenchmarkBase { - //public const string largeFilePath = @"D:\git\MiniExcel\samples\xlsx\Test1,000,000x10\Test1,000,000x10.xlsx"; - - public const string filePath = @"D:\git\MiniExcel\samples\xlsx\Test10x10.xlsx"; +#if !DEBUG + public const string filePath = @"D:\git\MiniExcel\samples\xlsx\Test1,000,000x10\Test1,000,000x10.xlsx"; + //public const string filePath = @"D:\git\MiniExcel\samples\xlsx\Test10x10.xlsx"; +#else + public const string filePath = @"D:\git\MiniExcel\samples\xlsx\Test1,000,000x10\Test1,000,000x10.xlsx"; + //public const string filePath = @"D:\git\MiniExcel\samples\xlsx\Test10x10.xlsx"; +#endif } - public class Benchmark: BenchmarkBase + public class XlsxBenchmark: BenchmarkBase { [GlobalSetup] public void SetUp() { + ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial; System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); } @@ -59,9 +64,21 @@ namespace MiniExcelLibs.Benchmarks MiniExcel.Query(filePath).First(); } + [Benchmark(Description = "MiniExcel Query")] + public void MiniExcel_Query() + { + foreach (var item in MiniExcel.Query(filePath)) + { + + } + } + [Benchmark(Description = "ExcelDataReader QueryFirst")] public void ExcelDataReader_QueryFirst_Test() { +#if DEBUG + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); +#endif using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read)) using (var reader = ExcelReaderFactory.CreateReader(stream)) { @@ -72,15 +89,58 @@ namespace MiniExcelLibs.Benchmarks } } + [Benchmark(Description = "ExcelDataReader Query")] + public void ExcelDataReader_Query_Test() + { +#if DEBUG + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); +#endif + using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read)) + using (var reader = ExcelReaderFactory.CreateReader(stream)) + { + while (reader.Read()) + { + var d = new List(); + for (int i = 0; i < reader.FieldCount; i++) + d.Add(reader.GetValue(i)); + } + } + } + [Benchmark(Description = "Epplus QueryFirst")] public void Epplus_QueryFirst_Test() { +#if DEBUG + ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial; +#endif using (var p = new ExcelPackage(new FileInfo(filePath))) { p.Workbook.Worksheets[0].Row(1); } } + [Benchmark(Description = "Epplus Query")] + public void Epplus_Query_Test() + { +#if DEBUG + ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial; +#endif + // [c# - How do I iterate through rows in an excel table using epplus? - Stack Overflow](https://stackoverflow.com/questions/21742038/how-do-i-iterate-through-rows-in-an-excel-table-using-epplus) + using (var p = new ExcelPackage(new FileInfo(filePath))) + { + var workSheet = p.Workbook.Worksheets[0]; + var start = workSheet.Dimension.Start; + var end = workSheet.Dimension.End; + for (int row = start.Row; row <= end.Row; row++) + { // Row by row... + for (int col = start.Column; col <= end.Column; col++) + { // ... Cell by cell... + object cellValue = workSheet.Cells[row, col].Text; // This got me the actual value I needed. + } + } + } + } + [Benchmark(Description = "ClosedXml QueryFirst")] public void ClosedXml_QueryFirst_Test() { @@ -90,6 +150,15 @@ namespace MiniExcelLibs.Benchmarks } } + [Benchmark(Description = "ClosedXml Query")] + public void ClosedXml_Query_Test() + { + using (var workbook = new XLWorkbook(filePath)) + { + workbook.Worksheet(1).Rows(); + } + } + [Benchmark(Description = "OpenXmlSDK QueryFirst")] public void OpenXmlSDK_QueryFirst_Test() { @@ -101,17 +170,137 @@ namespace MiniExcelLibs.Benchmarks var firstRow = sheetData.Elements().First(); } } - } - public class CreateTest - { - [Benchmark] + [Benchmark(Description = "OpenXmlSDK Query")] + public void OpenXmlSDK_Query_Test() + { + using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(filePath, false)) + { + WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart; + WorksheetPart worksheetPart = workbookPart.WorksheetParts.First(); + SheetData sheetData = worksheetPart.Worksheet.Elements().First(); + var firstRow = sheetData.Elements().ToList(); + } + } + + [Benchmark(Description = "MiniExcel Create Xlsx")] public void MiniExcelCreateTest() { - var values = Enumerable.Range(1, 10).Select((s, index) => new { index, value = Guid.NewGuid() }); + var values = GetValues(); var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx"); using (var stream = File.Create(path)) stream.SaveAs(values); + File.Delete(path); + } + + [Benchmark(Description = "ClosedXml Create Xlsx")] + public void ClosedXmlCreateTest() + { + var values = GetValues(); + var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx"); + using (var wb = new XLWorkbook()) + { + var ws = wb.Worksheets.Add("Inserting Data"); + ws.Cell(1, 1).InsertData(values); + wb.SaveAs(path); + } + + File.Delete(path); + } + + + [Benchmark(Description = "Epplus Create Xlsx")] + public void EpplusCreateTest() + { +#if DEBUG + ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial; +#endif + var values = GetValues(); + var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx"); + using (var excelFile = new ExcelPackage(new FileInfo(path))) + { + var worksheet = excelFile.Workbook.Worksheets.Add("Sheet1"); + worksheet.Cells["A1"].LoadFromCollection(Collection: values, PrintHeaders: true); + excelFile.Save(); + } + File.Delete(path); + } + + [Benchmark(Description = "OpenXmlSdk Create Xlsx")] + public void OpenXmlSdkCreateTest() + { + var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx"); + // Create a spreadsheet document by supplying the filepath. + // By default, AutoSave = true, Editable = true, and Type = xlsx. + + using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(path, SpreadsheetDocumentType.Workbook)) + { + // Add a WorkbookPart to the document. + WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart(); + workbookpart.Workbook = new Workbook(); + + // Add a WorksheetPart to the WorkbookPart. + WorksheetPart worksheetPart = workbookpart.AddNewPart(); + worksheetPart.Worksheet = new Worksheet(new SheetData()); + + // Add Sheets to the Workbook. + Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook. + AppendChild(new Sheets()); + + // Append a new worksheet and associate it with the workbook. + Sheet sheet = new Sheet() + { + Id = spreadsheetDocument.WorkbookPart. + GetIdOfPart(worksheetPart), + SheetId = 1, + Name = "Sheet1" + }; + sheets.Append(sheet); + + var sheetData = worksheetPart.Worksheet.GetFirstChild(); + foreach (var item in GetValues()) + { + var row = new Row(); + row.Append(new Cell() { CellValue = new CellValue(item.Text1), DataType = CellValues.String }); + row.Append(new Cell() { CellValue = new CellValue(item.Text2), DataType = CellValues.String }); + row.Append(new Cell() { CellValue = new CellValue(item.Text3), DataType = CellValues.String }); + row.Append(new Cell() { CellValue = new CellValue(item.Text4), DataType = CellValues.String }); + row.Append(new Cell() { CellValue = new CellValue(item.Text5), DataType = CellValues.String }); + row.Append(new Cell() { CellValue = new CellValue(item.Text6), DataType = CellValues.String }); + row.Append(new Cell() { CellValue = new CellValue(item.Text7), DataType = CellValues.String }); + row.Append(new Cell() { CellValue = new CellValue(item.Text8), DataType = CellValues.String }); + row.Append(new Cell() { CellValue = new CellValue(item.Text9), DataType = CellValues.String }); + row.Append(new Cell() { CellValue = new CellValue(item.Text10), DataType = CellValues.String }); + sheetData.AppendChild(row); + } + + workbookpart.Workbook.Save(); + + } + File.Delete(path); + } + + private static IEnumerable GetValues() + { +#if !DEBUG + return Enumerable.Range(1, 1000000).Select(s => new Demo()); +#else + return Enumerable.Range(1, 1000000).Select(s => new Demo()); +#endif + } + + public class Demo + { + public string Text1 { get; set; } = "Hello World"; + public string Text2 { get; set; } = "Hello World"; + public string Text3 { get; set; } = "Hello World"; + public string Text4 { get; set; } = "Hello World"; + public string Text5 { get; set; } = "Hello World"; + public string Text6 { get; set; } = "Hello World"; + public string Text7 { get; set; } = "Hello World"; + public string Text8 { get; set; } = "Hello World"; + public string Text9 { get; set; } = "Hello World"; + public string Text10 { get; set; } = "Hello World"; } } }