神秘的StringReader性能



我使用这里的实现对.NET和C#中的StringReader类进行了一些研究:https://referencesource.microsoft.com/#mscorlib/system/io/stringreader.cs

我制作了一个小类,我认为它使用了相同的基本实现来读取字符串,但令我惊讶的是,我的代码速度是.NET StringReader的两倍多。

这是我的课:

public class DataReader
{
private String source;
private int pos;
private int length;
public DataReader(string data)
{
source = data;
length = source.Length;
}
public int Peek()
{
if (pos == length) return -1;
return source[pos];
}
public int Read()
{
if (pos == length) return -1;
return source[pos++];
}
}

这是我的测试代码:

using System;
using System.IO;
using System.Diagnostics;
using System.Text;
using System.Collections.Generic;                   
public class Program
{
public static void Main()
{
var s = new String('x', 10000000);
StringReaderTest(s);

DataReaderTest(s);
}

private static void StringReaderTest(string s)
{
var stopwatch = new Stopwatch();

stopwatch.Start();

var reader = new StringReader(s);

while (reader.Peek() > -1)
{
reader.Read();
}

stopwatch.Stop();

Console.WriteLine(stopwatch.ElapsedMilliseconds);
}
private static void DataReaderTest(string s)
{
var stopwatch = new Stopwatch();

stopwatch.Start();
var reader = new DataReader(s);
while (reader.Peek() > -1)
{
reader.Read();
}
stopwatch.Stop();

Console.WriteLine(stopwatch.ElapsedMilliseconds);
}
}

这是整个事情的一个.NET版本。https://dotnetfiddle.net/MqbU5q

这是Fiddle的输出。我的实现速度慢了一倍。

77
159

我一定错过了什么,有人能解释一下吗?

因此,首先,Stopwatch不是一个合法的基准测试工具,它不合适的原因有很多。

您应该使用BenchmarkDotNet或类似的工具,预预热pre-JIT的在每次运行前收集垃圾,多次运行测试,并在调试时提醒您。

以下是如何生成更可靠基准的示例。

免责声明:在一个好的基准测试中,还有更多的事情需要推理,比如使用更真实的实际数据和用例表示

测试代码

[SimpleJob(RuntimeMoniker.Net60, baseline: true)]  
public class ReaderTest
{ 
private const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private string _s;
public static Random R = new(42);
[Params(1000, 10000, 100000)] public int N;
[GlobalSetup]
public void Setup() => _s = new string(Enumerable.Repeat(Chars, N).Select(s => s[R.Next(s.Length)]).ToArray());
public static void Main() => BenchmarkRunner.Run<ReaderTest>();
[Benchmark]
public int StringReader()
{
var stringReader = new StringReader(_s);
var result = 0;
while (stringReader.Peek() > -1)
result ^= stringReader.Read();
return result;
}
[Benchmark]
public int DataReader()
{
var dataReader = new DataReader(_s);
var result = 0;
while (dataReader.Peek() > -1)
result ^= dataReader.Read();      
return result;
}   
}

基准

环境

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19044.1348 (21H2)
Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
.NET SDK=6.0.100
[Host]   : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT  [AttachedDebugger]
.NET 6.0 : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
Job=.NET 6.0  Runtime=.NET 6.0

结果

>td style="text align:right>>td style="text align:right>7.2606 us
方法平均值
StringReader10003.424 us
10001.459 us0.0126 us0.0098 usStringReader100034.157 us
DataReader10000.0577 usStringReader100000348.650 us6.7857 us
DataReader100000146.257 us

相关内容

  • 没有找到相关文章

最新更新