前回、 ReadOnlySpan<T> と Range を駆使して高速に文字列分割*1する拡張メソッドを作り、そのベンチマークを行いました。
…が、「ベンチマークに BenchmarkDotNet を使わないとか舐めてるの?C#erの面汚しめ!」という心の声に悩まされるようになったので全面的に書き換えました。
GitHub: ruche7/Test_SplitReadOnlySpan at boyaki_200118 (以前のコードは boyaki_200110 タグにあります)
string を改行で区切って string[] にするまでの処理に絞って計測するようにした。
'\n' オンリーと "\r\n", "\n", "\r" 混合の2パターン。SpanExtensions 静的クラス(ReadOnlySpanExtensions から名前変更)に拡張メソッドを追加。
Span<T> に対応。ReadOnlySpan<char> と Span<char> 限定で複数セパレータ(string[])による分割に対応。(string.Split では元々可能)事前に下記の静的フィールドを準備しておきます。
|
計測対象メソッドは下記の4パターン。 N は上記フィールドの通り 1, 10, 100, 1000, 10000 の5通りで、総メソッド数は20個。
String_SplitNewLine_LineNLineN を string.Split('\n') で分割する。Span_SplitNewLine_LineNLineN を string.AsSpan() で ReadOnlySpan<char> に変換する。ReadOnlySpan<char>.SplitToRanges('\n') で各分割文字列範囲を表す List<Range> を得る。new string[ranges.Count] で作成した文字列配列に各行を span[ranges[i]].ToString() で設定。String_SplitLineBreaks_LineNLineN を string.Split(LineBreaks, StringSplitOptions.None) で分割する。Span_SplitLineBreaks_LineNLineN を string.AsSpan() で ReadOnlySpan<char> に変換する。ReadOnlySpan<char>.SplitToRanges(LineBreaks) で各分割文字列範囲を表す List<Range> を得る。new string[ranges.Count] で作成した文字列配列に各行を span[ranges[i]].ToString() で設定。要するに、 Xxx_SplitNewLine_LineN が単一セパレータ(char)による分割、
Xxx_SplitLineBreaks_LineN が複数セパレータ(string[])による分割です。
ベンチマークの結果は README.md に載せてあります。 Mean の列を見ればOK。
1行を単一セパレータで分割するケースを除き ReadOnlySpan<char>.SplitToRanges を使う方が高速で、特に複数セパレータの場合は2〜5倍もの速度差になっています。
自作のツール等では積極的に利用していきたいですね。