RegexOptions.Compiled
normal ifade motoruna normal ifade ifadesini hafif kod oluşturma ( LCG ) kullanarak IL'ye derleme talimatı verir . Bu derleme nesnenin yapımı sırasında olur ve ağır da yavaşlatır. Buna karşılık, normal ifadeyi kullanan eşleşmeler daha hızlıdır.
Bu bayrağı belirtmezseniz, normal ifadeniz "yorumlanır" olarak kabul edilir.
Bu örneği ele alalım:
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]);
});
}
}
3 farklı düzenli ifade üzerinde 4 test gerçekleştirir. Önce tek bir testi maç kapalı bir kere (derlenmiş olmayan vs derlenmiş). İkinci olarak, aynı normal ifadeyi yeniden kullanan tekrarlanan eşleşmeleri test eder.
Makinemdeki sonuçlar (sürümde derlenmiş, hata ayıklayıcı eklenmemiş)
1000 tekli maç (Regex, Match and dispose)
Türü | Platformu | Önemsiz Sayı | Basit E-posta Kontrolü | Dahili E-posta Kontrolü
-------------------------------------------------- ----------------------------
Yorumlandı | x86 | 4 ms | 26 ms | 31 ms
Yorumlandı | x64 | 5 ms | 29 ms | 35 ms
Derlendi | x86 | 913 ms | 3775 ms | 4487 ms
Derlendi | x64 | 3300 ms | 21985 ms | 22793 ms
1.000.000 eşleşme - Regex nesnesini yeniden kullanma
Türü | Platformu | Önemsiz Sayı | Basit E-posta Kontrolü | Dahili E-posta Kontrolü
-------------------------------------------------- ----------------------------
Yorumlandı | x86 | 422 ms | 461 ms | 2122 ms
Yorumlandı | x64 | 436 ms | 463 ms | 2167 ms
Derlendi | x86 | 279 ms | 166 ms | 1268 ms
Derlendi | x64 | 281 ms | 176 ms | 1180 ms
Bu sonuçlar, düzenli düzenli ifadelerin nesneyi yeniden kullandığınız durumlarda % 60'a kadar daha hızlı olabileceğini göstermektedir Regex
. Ancak bazı durumlarda 3'den fazla büyüklükte inşa edilebilir.
Ayrıca , normal ifadelerin derlenmesi söz konusu olduğunda , .NET'in x64 sürümünün 5 ila 6 kat daha yavaş olabileceğini gösterir .
Öneri olacaktır derlenmiş sürümünü kullanmak durumlarda nerede ya
- Nesne başlatma maliyetini umursamazsınız ve ekstra performans artışına ihtiyacınız vardır. (burada bir milisaniyelik kesirlerden bahsettiğimizi unutmayın)
- Başlatma maliyetine biraz önem veriyorsunuz, ancak Regex nesnesini uygulama ömrünüz boyunca telafi edecek kadar çok tekrar kullanıyorsunuz.
Eserler anahtar, Regex önbellek
Normal ifade motoru, Regex
sınıftaki statik yöntemler kullanılarak test edilen son 15 normal ifadeyi içeren bir LRU önbelleği içerir .
Örneğin: Regex.Replace
, Regex.Match
vb .. tüm kullanım Regex önbelleği.
Önbellek boyutu ayarlanarak artırılabilir Regex.CacheSize
. Uygulamanızın yaşam döngüsü boyunca herhangi bir zamanda boyut değişikliklerini kabul eder.
Yeni normal ifadeler yalnızca Regex sınıfındaki statik yardımcılar tarafından önbelleğe alınır . Nesnelerinizi oluşturursanız, önbellek kontrol edilir (yeniden kullanım ve çarpma için), oluşturduğunuz normal ifade önbelleğe eklenmez .
Bu önbellek önemsiz bir LRU önbelleğidir, basit bir çift bağlantılı liste kullanılarak uygulanır. Bunu 5000'e yükseltirseniz ve statik yardımcılarda 5000 farklı çağrı kullanırsanız, her normal ifade yapısı daha önce önbelleğe alınmış olup olmadığını görmek için 5000 girişi tarar. Kontrolün etrafında bir kilit vardır , bu nedenle kontrol paralelliği azaltabilir ve iplik blokajı sağlayabilir.
Kendinizi bu gibi durumlardan korumak için sayı oldukça düşüktür, ancak bazı durumlarda artırmak için başka seçeneğiniz olmayabilir.
Benim güçlü öneri olacağını asla geçmesi RegexOptions.Compiled
statik yardımcı seçeneği.
Örneğin:
\\ WARNING: bad code
Regex.IsMatch("10000", @"\\d+", RegexOptions.Compiled)
Bunun nedeni, LRU önbelleğinde süper pahalı bir derlemeyi tetikleyecek bir özlüyor olma riskini yüksek olmanızdır . Ayrıca, bağımlı olduğunuz kitaplıkların ne yaptığına dair hiçbir fikriniz yoktur, bu nedenle önbelleğin mümkün olan en iyi boyutunu denetleme veya tahmin etme konusunda çok az yeteneğiniz vardır .
Ayrıca bakınız: BCL takım blogu
Not : Bu, .NET 2.0 ve .NET 4.0 ile ilgilidir. 4.5'te bunun revize edilmesine neden olabilecek bazı değişiklikler var.