我的高级架构师告诉我,检验程序性能时不要用DateTime.Now相减或者StopWatch,最好用BenchmarkDotNet,于是我就试了一下。
上手体验后感觉BenchmarkDotNet大致的特点如下:
- 用起来还比较简单,在对应的method上面打上[Benchmark]标记即可;
- 通过var summary = BenchmarkRunner.Run();来启动;
- 要求class和method必须是public;
- 要求程序必须是Release;
- 会自动将程序中打标记的对应模块跑很多遍,最后给出均值和偏差;
使用前要在NuGet管理器中,或者在包管理器的PM终端中安装BenchmarkDotNet。
最后上代码(以测试SeriLog和原生StreamWriter的效率对比为例):
// See https://aka.ms/new-console-template for more information
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using Serilog;
using Serilog.Core;
SerilogTest.Program.main();
namespace SerilogTest
{
public class Program
{
Logger _log2Console = new LoggerConfiguration().WriteTo.Console().CreateLogger();
Logger _log2File = new LoggerConfiguration().WriteTo.File("seri.log").CreateLogger();
private StreamWriter _sw2File = new StreamWriter("sq.log");
private int _loopMaxTime = 100;
[Benchmark]
public double Seri2ConsoleI()
{
DateTime tmpStartTime = System.DateTime.Now;
for (int i = 1; i < _loopMaxTime; i++)
{
_log2Console.Information($"Serilog info {i}");
}
Log.CloseAndFlush();
DateTime tmpEndTime = System.DateTime.Now;
TimeSpan tmpTimeCost = tmpEndTime.Subtract(tmpStartTime);
return Math.Round(tmpTimeCost.TotalMilliseconds, 2, MidpointRounding.AwayFromZero);
}
[Benchmark]
public double Seri2ConsoleE()
{
DateTime tmpStartTime = System.DateTime.Now;
for (int i = 1; i < _loopMaxTime; i++)
{
_log2Console.Error($"Serilog error {i}");
}
Log.CloseAndFlush();
DateTime tmpEndTime = System.DateTime.Now;
TimeSpan tmpTimeCost = tmpEndTime.Subtract(tmpStartTime);
return Math.Round(tmpTimeCost.TotalMilliseconds, 2, MidpointRounding.AwayFromZero);
}
[Benchmark]
public double Seri2FileI()
{
DateTime tmpStartTime = System.DateTime.Now;
for (int i = 1; i < _loopMaxTime; i++)
{
_log2File.Information($"Serilog info {i}");
}
Log.CloseAndFlush();
DateTime tmpEndTime = System.DateTime.Now;
TimeSpan tmpTimeCost = tmpEndTime.Subtract(tmpStartTime);
return Math.Round(tmpTimeCost.TotalMilliseconds, 2, MidpointRounding.AwayFromZero);
}
[Benchmark]
public double Seri2FileE()
{
DateTime tmpStartTime = System.DateTime.Now;
for (int i = 1; i < _loopMaxTime; i++)
{
_log2File.Error($"Serilog error {i}");
}
Log.CloseAndFlush();
DateTime tmpEndTime = System.DateTime.Now;
TimeSpan tmpTimeCost = tmpEndTime.Subtract(tmpStartTime);
return Math.Round(tmpTimeCost.TotalMilliseconds, 2, MidpointRounding.AwayFromZero);
}
[Benchmark]
public double Stream2File()
{
DateTime tmpStartTime = System.DateTime.Now;
for (int i = 1; i < _loopMaxTime; i++)
{
_sw2File.WriteLine($"{tmpStartTime.ToString()}.077 +08:00 [ERR] Stream Writer {i}");
}
_sw2File.Flush();
DateTime tmpEndTime = System.DateTime.Now;
TimeSpan tmpTimeCost = tmpEndTime.Subtract(tmpStartTime);
return Math.Round(tmpTimeCost.TotalMilliseconds, 2, MidpointRounding.AwayFromZero);
}
[Benchmark]
public double Stream2Console()
{
DateTime tmpStartTime = System.DateTime.Now;
for (int i = 1; i < _loopMaxTime; i++)
{
Console.WriteLine($"{tmpStartTime.ToString()}.077 +08:00 [ERR] Console Write {i}");
}
DateTime tmpEndTime = System.DateTime.Now;
TimeSpan tmpTimeCost = tmpEndTime.Subtract(tmpStartTime);
return Math.Round(tmpTimeCost.TotalMilliseconds, 2, MidpointRounding.AwayFromZero);
}
public static void main()
{
var summary = BenchmarkRunner.Run<Program>();
/*
double SeriConcolsErrorCost = Seri2ConsoleE();
double SeriConcolsInfoCost = Seri2ConsoleI();
double SeriFileErrorCost = Seri2FileE();
double SeriFileInfoCost = Seri2FileI();
double SystConsoleInfoCost = Stream2Console();
double SystFileInfoCost = Stream2File();
Console.WriteLine($"[To Console]:\n" +
$" Seri info: { SeriConcolsInfoCost }ms\n" +
$" Seri err: { SeriConcolsErrorCost }ms\n" +
$" Sys output: { SystConsoleInfoCost }ms\n" +
$"[To file]:\n" +
$" Seri info: { SeriFileInfoCost }ms\n" +
$" Seri error: { SeriFileErrorCost }ms\n" +
$" Sys output: { SystFileInfoCost }ms\n");
*/
}
}
}
运行结果如下:
结果日志也会保存在新生成的BenchmarkDotNet.Artifacts目录中。