Regexクラスの仕様
今回の話
既定では、正規表現エンジンは、内部命令のシーケンス (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 クラスはスレッドセーフであり、変更はできないものらしい
Regex クラス自体はスレッド セーフであり、変更できません (読み取り専用)。
つまり、Regex オブジェクトは任意のスレッドで作成できます。また、スレッド間で共有できます。 一致するメソッドは任意のスレッドから呼び出すことができますが、グ>ローバルな状態を変更することはできません。
なので、Regex クラスで正規表現のオブジェクトを生成する場合は命じて敵に readonly をつけた方がよいかもしれない
static readonly Regex reg = new Regex(@"[a-z]");