FC2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム »2021年04月
2021年04月の記事一覧

【Unity】【C#】StartsWith, EndsWith が遅いのなら、Equals も遅いのか?  


 Unity の公式マニュアルにも掲載されているのだが(ただし、情報が少し古い[Unity5])、文字列比較の StartsWith, EndsWith は遅いというのは以前から言われていた。実際に、そのページにある「CustomStartsWith」と「CustomEndsWith」と、標準ライブラリの StartsWith, EndsWith の速度比較をしてみると、かなり遅い。

文字列とテキスト - 非効率的なビルトイン String API

 ただ、その理由を読んでいたら「比較にはローカライズ用のデフォルトカルチャが効いているから」という事らしい(解説には Equals では "encyclopedia", "encyclopædia" のような表記違いは等価とみなすとある)。

 「あれ?それなら Equals も CustomEquals を作った方が良いのでは?」と思ったので、試しに作ってみた。といっても CustomStartsWith とほぼ同じなんだけどね。そしてその速度比較の結果を残しておこう。

(※) Unity 2019.4.21f1 [.NET 4.x] / Windows10(x64) で確認



●公式の CustomStartsWith を真似した単純な Equals
using System;

public static class Extentions //※名前は任意
{
/// <summary>
/// 公式の CustomStartsWith を真似した単純な Equals.
/// https://docs.unity3d.com/ja/current/Manual/BestPracticeUnderstandingPerformanceInUnity5.html
/// </summary>
public static bool CustomEquals(this string a, string b)
{
int aLen = a.Length;
if (aLen != b.Length)
return false;

int ap = 0;
while (ap < aLen && a [ap] == b [ap])
{
ap++;
}

return (ap == aLen);
}
}

 また比較には、公式の解説にある「ローカライズ用の調整を必要としない文字列比較に StringComparison.Ordinal を推奨」ともあったので、ついでに加えてみた(また Equals ではオペレータの "==" も加えてある)。以下に比較結果を載せておこう。

●StartsWith, EndsWith, Equlas の標準と Ordinal オプションと Custom~ を 100000 回×10回実行して、平均値を計測
●StartsWith
[StandardStartsWith] ave : 0.1930909 [sec]
[StandardStartsWithOrdinal] ave : 0.08576998 [sec]
[CustomStartsWith] ave : 0.08573665 [sec]

●EndsWith
[StandardEndsWith] ave : 1.135096 [sec]
[StandardEndsWithOrdinal] ave : 0.08583274 [sec]
[CustomEndsWith] ave : 0.0840721 [sec]

●Equals
[StandardEquals] ave : 0.09371759 [sec]
[StandardEqualsOrdinal] ave : 0.09588816 [sec]
[OperatorEquals] ave : 0.09638711 [sec]
[CustomEquals] ave : 0.09519003 [sec]

 コンパイルは「.NET 4.x」でやってるからか、意外なことに、特に Equals では誤差範囲くらいしか変わらなかった(ただし、半角英数や日本語だけの場合。他の言語では違いは出るのかも?)。

 Custom~ のメソッドには null チェックも付いてないので、それを追加したとしても大して変化は無い。結果を見てみると、どうやら .NET 4.x で日本語や英字ぐらいの範囲なら、StringComparison.Ordinal オプションを付ければ、実行速度は速いらしい。

 もちろん文字列の内容や長さにもよるだろうが、私が試した限りでは、10~100文字程度で日本語・英語混合くらいなら、ほとんど誤差範囲でしか変わらない。なので「a.StartsWith(b, StringComparison.Ordinal)」「a.EndsWith(b, StringComparison.Ordinal)」「a.Equals(b, StringComparison.Ordinal) (※a.Equlas(b) でもなぜか変わらない)」を機械的に使っても、実質問題無いようだ。

 まぁ、標準ライブラリ自体も改修されているからね。Unity の公式マニュアルは Unity5 時代で .NET 3.5 だったので、多少は変わったのかも知れない(実際に .NET 4.x になって GC 発生やコルーチンなども改修されてるとか何とか…)。

GCの発生要因を減らす

 特に古い情報の場合、一度現在のバージョン・環境で試してみるのも良いかもね。ちなみに Android でやってみても、同じような結果だった。現バージョンでは普段使いなら、Ordinal オプションを付けておけば、Custom~ は必要ないようだ。





(関連記事)
【Unity】【C#】文字列の内容をシャッフルする
【Unity】【C#】文字列の暗号化・復号化を簡単に行う
【C#】クラスのフィールド名を文字列の配列で取得する


関連記事
スポンサーサイト



category: Unity

thread: プログラミング

janre: コンピュータ

tag: C#ライブラリ  文字列操作  検証 
tb: 0   cm: --


プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop