なんかいろいろと書いてくブログ

関東のどこかで働く、一般人

【C#】Regexクラスの RegexOptions.Compiled

Regexクラスの仕様

docs.microsoft.com

今回の話

docs.microsoft.com

既定では、正規表現エンジンは、内部命令のシーケンス (Microsoft 中間言語 (MSIL) とは異なる高度なコード) に正規表現をコンパイルします。
エンジンは、正規表現を実行するときに内部コードを解釈します。

Regex クラスは正規表現を内部命シーケンスにコンパイル後、
isMatch のような正規表現を使用するたびに内部命令シーケンスを解釈しているため、 実行コストが重くなりやすい。

そのため、Regex クラスにはRegexOptions.Compiledオプションがあり、 指定すると明示的な MSIL コードに正規表現をコンパイルするため、 コンパイルコストが重くなるが、実行コストは下がる

実際、下記のようにRegexOptions.Compiledオプションを指定した場合と、 指定しないばあいの正規表現オブジェクトで isMatch による判定を 5億回行うと明らかにオプション指定した方がややではあるがオプション指定した方が早かった

using System;
using System.Text.RegularExpressions;
using System.Diagnostics;

public class Program
{
    public static void Main()
    {
        var repeat = 500000000;
        var hoge = "hogehoge";

        // Compiled オプションなし
        var sw1 = new Stopwatch();
        sw1.Start();

        var reg1 = new Regex(@"[a-z]");
        for (int i = 0; i < repet; i++)
        {
            reg1.IsMatch(hoge);
        }
        sw1.Stop();
        Console.WriteLine($"result {sw1.ElapsedMilliseconds} ms");

        // Compiled オプションあり
        var sw2 = new Stopwatch();
        sw2.Start();

        var reg2 = new Regex(@"[a-z]", RegexOptions.Compiled);
        for (int i = 0; i < repet; i++)
        {
            reg1.IsMatch(hoge);
        }
        sw2.Stop();
        Console.WriteLine($"use compile option. result {sw2.ElapsedMilliseconds} ms");
    }
}

結果

また、Regex クラスはスレッドセーフであり、変更はできないものらしい

docs.microsoft.com

Regex クラス自体はスレッド セーフであり、変更できません (読み取り専用)。
つまり、Regex オブジェクトは任意のスレッドで作成できます。また、スレッド間で共有できます。 一致するメソッドは任意のスレッドから呼び出すことができますが、グ>ローバルな状態を変更することはできません。

なので、Regex クラスで正規表現のオブジェクトを生成する場合は命じて敵に readonly をつけた方がよいかもしれない

static readonly Regex reg = new Regex(@"[a-z]");