RegexOptions.Compiled
indique au moteur d'expressions régulières de compiler l'expression régulière en IL à l'aide de la génération de code légère ( LCG ). Cette compilation se fait pendant la construction de l'objet et lourdement le ralentit. En revanche, les correspondances utilisant l'expression régulière sont plus rapides.
Si vous ne spécifiez pas ce drapeau, votre expression régulière est considérée comme "interprétée".
Prenez cet exemple :
public static void TimeAction(string description, int times, Action func)
{
// warmup
func();
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < times; i++)
{
func();
}
watch.Stop();
Console.Write(description);
Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
}
static void Main(string[] args)
{
var simple = "^\\d+$";
var medium = @"^((to|from)\W)?(?<url>http://[\w\.:]+)/questions/(?<questionId>\d+)(/(\w|-)*)?(/(?<answerId>\d+))?";
var complex = @"^(([^<>()[\]\\.,;:\s@""]+"
+ @"(\.[^<>()[\]\\.,;:\s@""]+)*)|("".+""))@"
+ @"((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
+ @"\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+"
+ @"[a-zA-Z]{2,}))$";
string[] numbers = new string[] {"1","two", "8378373", "38737", "3873783z"};
string[] emails = new string[] { "sam@sam.com", "sss@s", "sjg@ddd.com.au.au", "onelongemail@oneverylongemail.com" };
foreach (var item in new[] {
new {Pattern = simple, Matches = numbers, Name = "Simple number match"},
new {Pattern = medium, Matches = emails, Name = "Simple email match"},
new {Pattern = complex, Matches = emails, Name = "Complex email match"}
})
{
int i = 0;
Regex regex;
TimeAction(item.Name + " interpreted uncached single match (x1000)", 1000, () =>
{
regex = new Regex(item.Pattern);
regex.Match(item.Matches[i++ % item.Matches.Length]);
});
i = 0;
TimeAction(item.Name + " compiled uncached single match (x1000)", 1000, () =>
{
regex = new Regex(item.Pattern, RegexOptions.Compiled);
regex.Match(item.Matches[i++ % item.Matches.Length]);
});
regex = new Regex(item.Pattern);
i = 0;
TimeAction(item.Name + " prepared interpreted match (x1000000)", 1000000, () =>
{
regex.Match(item.Matches[i++ % item.Matches.Length]);
});
regex = new Regex(item.Pattern, RegexOptions.Compiled);
i = 0;
TimeAction(item.Name + " prepared compiled match (x1000000)", 1000000, () =>
{
regex.Match(item.Matches[i++ % item.Matches.Length]);
});
}
}
Il effectue 4 tests sur 3 expressions régulières différentes. Il teste d'abord une simple une correspondance unique (compilée ou non). Ensuite, il teste les correspondances répétées qui réutilisent la même expression régulière.
Les résultats sur ma machine (compilé en release, pas de débogueur attaché)
1000 correspondances simples (construction de Regex, Match and dispose)
Type | Platform | Trivial Number | Simple Email Check | Ext Email Check
------------------------------------------------------------------------------
Interpreted | x86 | 4 ms | 26 ms | 31 ms
Interpreted | x64 | 5 ms | 29 ms | 35 ms
Compiled | x86 | 913 ms | 3775 ms | 4487 ms
Compiled | x64 | 3300 ms | 21985 ms | 22793 ms
1 000 000 de correspondances - réutilisation de l'objet Regex
Type | Platform | Trivial Number | Simple Email Check | Ext Email Check
------------------------------------------------------------------------------
Interpreted | x86 | 422 ms | 461 ms | 2122 ms
Interpreted | x64 | 436 ms | 463 ms | 2167 ms
Compiled | x86 | 279 ms | 166 ms | 1268 ms
Compiled | x64 | 281 ms | 176 ms | 1180 ms
Ces résultats montrent que les expressions régulières compilées peuvent aller jusqu'à 60% plus rapide pour les cas où vous réutilisez le Regex
objet. Cependant dans certains cas, peut être supérieur 3 ordres de grandeur plus lente à construire.
Il montre également que le version x64 de .NET peut être 5 à 6 fois plus lent lorsqu'il s'agit de la compilation d'expressions régulières.
La recommandation serait la suivante utiliser la version compilée dans les cas où soit
- Vous ne vous souciez pas du coût d'initialisation de l'objet et vous avez besoin d'une augmentation supplémentaire des performances. (Notez que nous parlons ici de fractions de millisecondes).
- Vous vous souciez un peu du coût d'initialisation, mais vous réutilisez l'objet Regex tellement de fois qu'il compensera ce coût au cours du cycle de vie de votre application.
Le cache Regex, un élément clé de la stratégie de l'UE
Le moteur d'expressions régulières contient un cache LRU qui contient les 15 dernières expressions régulières qui ont été testées à l'aide des méthodes statiques sur le site Web de l'entreprise. Regex
classe.
Par exemple : Regex.Replace
, Regex.Match
etc. utilisent tous le cache Regex.
La taille du cache peut être augmentée en définissant Regex.CacheSize
. Il accepte les changements de taille à tout moment au cours du cycle de vie de votre application.
Les nouvelles expressions régulières sont uniquement mises en cache par les aides statiques sur la classe Regex. Si vous construisez vos objets, le cache est vérifié (pour la réutilisation et le bumped), cependant, l'expression régulière que vous construisez est ne sont pas ajoutés au cache .
Ce cache est un trivial Cache LRU, il est implémenté en utilisant une simple liste doublement liée. Si vous l'augmentez à 5000, et utilisez 5000 appels différents sur les aides statiques, chaque construction d'expression régulière va parcourir les 5000 entrées pour voir si elle a déjà été mise en cache. Il existe un serrure autour de la vérification, de sorte que la vérification peut réduire le parallélisme et introduire le blocage des threads.
Ce chiffre est fixé assez bas pour vous protéger de ce genre de cas, bien que dans certains cas vous n'ayez pas d'autre choix que de l'augmenter.
Mon forte recommandation serait jamais passer le RegexOptions.Compiled
à une aide statique.
Par exemple :
\\ WARNING: bad code
Regex.IsMatch("10000", @"\\d+", RegexOptions.Compiled)
La raison en est que vous risquez fortement de rater le cache LRU, ce qui déclenchera un message d'erreur. très cher compiler. De plus, vous n'avez aucune idée de ce que font les bibliothèques dont vous dépendez, et vous n'avez donc que peu de possibilités de contrôler ou de prédire l'évolution de la le meilleur possible la taille du cache.
Voir aussi : Blog de l'équipe du BCL
Note : ceci est pertinent pour .NET 2.0 et .NET 4.0. Certains changements attendus dans la version 4.5 pourraient entraîner une révision de ce document.
0 votes
Bonne ressource sur les meilleures pratiques en matière de Regex : docs.microsoft.com/fr/us/dotnet/standard/base-types/