.NET Core 2.1 で String.Split は早くなっているか?
Qiitaより転載
2018/4/26 初投稿
最近 .NET Core 2.1 preview が盛んらしいので実験。
そういえばどこかで .NET Core 2.1 では Span<T>
が入るから、String.Split
が早くなる、みたいなことを聞いた気がしたのでベンチマーク。
テストコード
/* using は省略 */
namespace csharp
{
class Program
{
static void Main(string[] args)
{
BenchmarkRunner.Run<Test>(new BenchmarkConfig());
}
}
public class BenchmarkConfig : ManualConfig
{
public BenchmarkConfig()
{
Add(SetRun(Job.Default.UnfreezeCopy()));
Add(DefaultColumnProviders.Instance);
Add(MarkdownExporter.GitHub);
Add(new ConsoleLogger());
Add(new HtmlExporter());
Add(MemoryDiagnoser.Default);
}
private static Job SetRun(Job job)
{
job.Run.UnrollFactor = 5;
job.Run.InvocationCount = 5;
job.Run.WarmupCount = 1;
job.Run.TargetCount = 1;
job.Run.LaunchCount = 30;
return job;
}
}
public class Test
{
private readonly string Str = "hoge,fuga,moge";
[Benchmark]
public (string, string) UsingSplit()
{
var split = Str.Split(",");
return (split[0], split[2]);
}
[Benchmark]
public (string, string) UsingSpanSplit()
{
IEnumerable<Span> LineSplitter(string s, char separator)
{
int offset = 0;
int length = 0;
for (int i = 0; i < s.Length; i++)
{
length++;
if (s[i] == separator)
{
yield return new Span { Offset = offset, Length = length - 1, Value = s };
offset = i + 1;
length = 0;
}
}
}
using(var enumerator = LineSplitter(Str, ',').GetEnumerator())
{
enumerator.MoveNext();
var a = enumerator.Current.Substring();
enumerator.MoveNext();
enumerator.MoveNext();
var b = enumerator.Current.Substring();
return (a, b);
}
}
}
public struct Span
{
public string Value { get; set; }
public int Offset { get; set; }
public int Length { get; set; }
public string Substring() => Value.Substring(Offset, Length);
}
}
"hoge,fuga,moge"
を分割して、"hoge"
と "moge"
だけ持ってくる時間を計ってみました。
普通にテストするだけだと面白くないので、オレオレ Span
を使った実装も含んでます。MoveNext
があんま美しくないけど。
結果
.NET Core 2.0
BenchmarkDotNet=v0.10.14, OS=Windows 10.0.16299.371 (1709/FallCreatorsUpdate/Redstone3)
Intel Core i5-5200U CPU 2.20GHz (Broadwell), 1 CPU, 4 logical and 2 physical cores
Frequency=2143478 Hz, Resolution=466.5315 ns, Timer=TSC
.NET Core SDK=2.1.300-preview2-008533
[Host] : .NET Core 2.0.6 (CoreCLR 4.6.26212.01, CoreFX 4.6.26212.01), 64bit RyuJIT
Job-FMXLHV : .NET Core 2.0.6 (CoreCLR 4.6.26212.01, CoreFX 4.6.26212.01), 64bit RyuJIT
InvocationCount=5 LaunchCount=30 TargetCount=1
UnrollFactor=5 WarmupCount=1
Method | Mean | Error | StdDev | Allocated |
--------------- |---------:|----------:|----------:|----------:|
UsingSplit | 1.439 us | 0.6936 us | 1.0381 us | 0 B |
UsingSpanSplit | 1.046 us | 0.3128 us | 0.4681 us | 0 B |
.NET Core 2.1
BenchmarkDotNet=v0.10.14, OS=Windows 10.0.16299.371 (1709/FallCreatorsUpdate/Redstone3)
Intel Core i5-5200U CPU 2.20GHz (Broadwell), 1 CPU, 4 logical and 2 physical cores
Frequency=2143478 Hz, Resolution=466.5315 ns, Timer=TSC
.NET Core SDK=2.1.300-preview2-008533
[Host] : .NET Core 2.1.0-preview2-26406-04 (CoreCLR 4.6.26406.07, CoreFX 4.6.26406.04), 64bit RyuJIT
Job-VJIIGD : .NET Core 2.1.0-preview2-26406-04 (CoreCLR 4.6.26406.07, CoreFX 4.6.26406.04), 64bit RyuJIT
InvocationCount=5 LaunchCount=30 TargetCount=1
UnrollFactor=5 WarmupCount=1
Method | Mean | Error | StdDev | Allocated |
--------------- |---------:|----------:|----------:|----------:|
UsingSplit | 1.175 us | 0.3757 us | 0.5624 us | 0 B |
UsingSpanSplit | 1.005 us | 0.3680 us | 0.5508 us | 0 B |
うむ、20% 近く早くなってるね。でもこれは Split
が早くなってるのかランタイムが早くなってるのかわからんね。
オレオレ Span
の Split
は関係なく早かった。Substring
自体が遅いのかな、と想像。
Split
の実装見たほうが早そう。
Discussion