RegexOptions.Compiled कैसे काम करता है?


169

जब आप संकलित होने के लिए एक नियमित अभिव्यक्ति को चिह्नित करते हैं तो पर्दे के पीछे क्या चल रहा है? कैश्ड नियमित अभिव्यक्ति से यह कैसे तुलना / भिन्न है?

इस जानकारी का उपयोग करते हुए, आप कैसे निर्धारित करते हैं कि प्रदर्शन वृद्धि की तुलना में गणना की लागत नगण्य है?


रेगेक्स सर्वोत्तम प्रथाओं पर अच्छा संसाधन: docs.microsoft.com/en-us/dotnet/standard/base-types/…
CAD

जवाबों:


302

RegexOptions.Compiledलाइट कोड पीढ़ी ( LCG ) का उपयोग करके नियमित अभिव्यक्ति अभिव्यक्ति को IL में संकलित करने के लिए नियमित अभिव्यक्ति इंजन को निर्देश देता है । इस संकलन वस्तु के निर्माण के दौरान होता है और भारी यह धीमा। बदले में, नियमित अभिव्यक्ति का उपयोग करने वाले मैच तेज होते हैं।

यदि आप इस ध्वज को निर्दिष्ट नहीं करते हैं, तो आपकी नियमित अभिव्यक्ति को "व्याख्या" माना जाता है।

इस उदाहरण को लें:

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 अलग-अलग नियमित अभिव्यक्तियों पर 4 परीक्षण करता है। पहले यह एक बार ऑफ मैच (संकलित बनाम गैर संकलित) का एकल परीक्षण करता है । दूसरा यह दोहराए गए मैचों का परीक्षण करता है जो समान नियमित अभिव्यक्ति का पुन: उपयोग करते हैं।

मेरी मशीन पर परिणाम (जारी में संकलित, कोई डिबगर संलग्न नहीं)

1000 एकल मैच (रेगेक्स का निर्माण, मिलान और निपटान)

प्रकार | प्लेटफार्म | तुच्छ संख्या | सरल ईमेल जाँच | ईमेल की जाँच करें
-------------------------------------------------- ----------------------------
व्याख्या की गई | x86 | 4 एमएस | 26 एमएस | ३१ मि
व्याख्या की गई | x64 | 5 एमएस | 29 एमएस | 35 एमएस
संकलित | x86 | 913 एमएस | 3775 एमएस | 4487 मि
संकलित | x64 | 3300 एमएस | 21985 एमएस | 22793 मि

1,000,000 मैच - रेगेक्स ऑब्जेक्ट का पुन: उपयोग

प्रकार | प्लेटफार्म | तुच्छ संख्या | सरल ईमेल जाँच | ईमेल की जाँच करें
-------------------------------------------------- ----------------------------
व्याख्या की गई | x86 | 422 एमएस | 461 एमएस | 2122 मि
व्याख्या की गई | x64 | 436 एमएस | 463 एमएस | 2167 मि
संकलित | x86 | 279 एमएस | 166 एमएस | 1268 मि
संकलित | x64 | 281 एमएस | 176 एमएस | 1180 मि

ये परिणाम बताते हैं कि संकलित नियमित अभिव्यक्तियाँ उन मामलों के लिए 60% तक तेज हो सकती हैं जहां आप Regexऑब्जेक्ट का पुन: उपयोग करते हैं । हालांकि कुछ मामलों में निर्माण के लिए परिमाण धीमे के 3 से अधिक आदेश हो सकते हैं ।

यह भी दर्शाता है कि .NET का x64 संस्करण नियमित अभिव्यक्ति के संकलन की बात आने पर 5 से 6 गुना धीमा हो सकता है।


सिफारिश उन मामलों में संकलित संस्करण का उपयोग करने के लिए होगी जहां या तो

  1. आपको ऑब्जेक्ट आरंभीकरण लागत के बारे में परवाह नहीं है और अतिरिक्त प्रदर्शन को बढ़ावा देने की आवश्यकता है। (ध्यान दें कि हम यहाँ एक मिलीसेकंड के अंशों की बात कर रहे हैं)
  2. आप आरंभीकरण लागत के बारे में थोड़ा ध्यान रखते हैं, लेकिन रेगेक्स ऑब्जेक्ट को इतनी बार पुन: उपयोग कर रहे हैं कि यह आपके आवेदन जीवन चक्र के दौरान इसके लिए क्षतिपूर्ति करेगा।

कार्यों में स्पैनर, रेगेक्स कैश

नियमित अभिव्यक्ति इंजन में एक LRU कैश होता है जो पिछले 15 नियमित अभिव्यक्तियों को रखता है जिन्हें Regexकक्षा पर स्थिर तरीकों का उपयोग करके परीक्षण किया गया था ।

उदाहरण के लिए: Regex.Replace, Regex.Matchआदि .. सभी उपयोग Regex कैश।

सेटिंग के द्वारा कैशे का आकार बढ़ाया जा सकता है Regex.CacheSize। यह आपके आवेदन के जीवन चक्र के दौरान किसी भी समय आकार में परिवर्तन को स्वीकार करता है।

नई नियमित अभिव्यक्तियाँ केवल रेगेक्स वर्ग पर स्थैतिक सहायकों द्वारा रखी गई हैं । यदि आप अपनी वस्तुओं का निर्माण करते हैं तो कैश की जांच की जाती है (पुन: उपयोग और टक्कर के लिए), हालांकि, आपके द्वारा निर्मित नियमित अभिव्यक्ति कैश में संलग्न नहीं होती है

यह कैश एक तुच्छ LRU कैश है, यह एक साधारण डबल लिंक्ड सूची का उपयोग करके कार्यान्वित किया जाता है। यदि आप इसे 5000 तक बढ़ाने के लिए होते हैं, और स्थिर सहायकों पर 5000 विभिन्न कॉल का उपयोग करते हैं, तो हर नियमित अभिव्यक्ति निर्माण यह देखने के लिए 5000 प्रविष्टियों को क्रॉल करेगा कि क्या यह पहले से कैश किया गया है। चेक के चारों ओर एक लॉक होता है, इसलिए चेक समानांतरता को कम कर सकता है और थ्रेड ब्लॉकिंग की शुरुआत कर सकता है।

इस तरह के मामलों से खुद को बचाने के लिए संख्या काफी कम है, हालांकि कुछ मामलों में आपके पास इसे बढ़ाने के अलावा कोई विकल्प नहीं हो सकता है।

मेरे मजबूत सिफारिश की जाएगी कभी नहीं पारित RegexOptions.Compiledएक स्थिर सहायक के लिए विकल्प।

उदाहरण के लिए:

\\ WARNING: bad code
Regex.IsMatch("10000", @"\\d+", RegexOptions.Compiled)

इसका कारण यह है कि आप LRU कैश पर एक बड़ी चूक कर रहे हैं जो एक सुपर महंगी संकलन को ट्रिगर करेगा । इसके अतिरिक्त, आपके पास यह पता नहीं है कि आपके द्वारा निर्भर पुस्तकालय क्या कर रहे हैं, इसलिए कैश के सर्वोत्तम संभावित आकार को नियंत्रित करने या भविष्यवाणी करने की बहुत कम क्षमता है ।

इसे भी देखें: BCL टीम ब्लॉग


नोट : यह .NET 2.0 और .NET 4.0 के लिए प्रासंगिक है। 4.5 में कुछ अपेक्षित बदलाव हैं जो इसे संशोधित कर सकते हैं।


11
बहुत बढ़िया जवाब। अपने स्वयं के प्रयोजनों के लिए मैं अक्सर Compiledवेबसाइट कोड में उपयोग करता हूं, जहां मैं वास्तव में एक स्थिर (एप्लिकेशन-वाइड) Regexऑब्जेक्ट स्टोर कर रहा हूं । तो Regexकेवल एक बार निर्माण करना होगा जब IIS आवेदन शुरू करता है, और फिर हजारों बार पुन: उपयोग किया जाता है। यह तब तक अच्छी तरह से काम करता है जब तक कि एप्लिकेशन अक्सर पुनरारंभ नहीं होता है।
स्टीव वॉर्थम

W00! इस जानकारी ने मुझे मेरी प्रक्रिया को 8-13 घंटे से ~ 30 मिनट तक गति देने में मदद की। धन्यवाद!
राबर्ट मसीह

3
महान उत्तर सैम, क्या आप संस्करण> 4.5 में बदल गए हैं, इस बारे में अपडेट कर सकते हैं? (मुझे पता है कि आपने कुछ समय पहले अपना स्टैक बदल दिया था ...)
गॉर्डन मोनिका

@gdoronissupportingMonica NET 5.0 पर कुछ Regex प्रदर्शन में सुधार हुआ है। मैंने इसके लिए एक ब्लॉग पोस्ट देखी। आप इसे यहाँ
kapozade

42

बीसीएल टीम ब्लॉग में यह प्रविष्टि एक अच्छा अवलोकन देती है: " नियमित अभिव्यक्ति प्रदर्शन "।

संक्षेप में, तीन प्रकार के रेगेक्स हैं (प्रत्येक पिछले एक की तुलना में तेजी से निष्पादित):

  1. व्याख्या की

    उड़ान भरने के लिए तेजी से, निष्पादित करने के लिए धीमी गति से

  2. संकलित (जिसके बारे में आप पूछना चाहते हैं)

    धीमी गति से उड़ान भरने के लिए, निष्पादन के लिए तेज़ (छोरों में निष्पादन के लिए अच्छा)

  3. पूर्व संकलित

    अपने एप्लिकेशन के संकलन समय पर बनाएं (कोई रन-टाइम निर्माण दंड नहीं), निष्पादित करने के लिए तेज़

इसलिए, यदि आप केवल एक बार या अपने ऐप के गैर-प्रदर्शन-महत्वपूर्ण अनुभाग (यानी उपयोगकर्ता इनपुट सत्यापन) में रेगेक्स को निष्पादित करने का इरादा रखते हैं, तो आप विकल्प 1 के साथ ठीक हैं।

यदि आप रेगेक्स को लूप में चलाने का इरादा रखते हैं (फ़ाइल की लाइन-बाय-लाइन पार्सिंग), तो आपको विकल्प 2 पर जाना चाहिए।

यदि आपके पास कई regexes हैं जो आपके ऐप के लिए कभी नहीं बदलेंगे और तीव्रता से उपयोग किए जाते हैं, तो आप विकल्प 3 के साथ जा सकते हैं।


1
नंबर 3 को कस्टम रोज़लिन के माध्यम से आसान बनाया जा सकता हैCompileModule । लानत है, मुझे नए प्लैटफॉर्म में गहराई से देखने की ज़रूरत है।
क्रिश्चियन गोल्हार्ट

9

यह ध्यान दिया जाना चाहिए कि .NET 2.0 के बाद से नियमित अभिव्यक्तियों के प्रदर्शन में बिना किसी नियमित अभिव्यक्ति के MRU कैश के साथ सुधार किया गया है। रेगेक्स लाइब्रेरी कोड अब हर बार एक ही संयुक्त-संकलित नियमित अभिव्यक्ति को पुनः स्थापित नहीं करता है।

इसलिए संकलित और मक्खी नियमित अभिव्यक्ति के साथ संभावित रूप से एक बड़ा प्रदर्शन जुर्माना है । धीमी लोड अवधि के अलावा, सिस्टम अधिक मेमोरी का उपयोग करता है ताकि नियमित अभिव्यक्ति को ऑपकोड में संकलित किया जा सके।

अनिवार्य रूप से, वर्तमान सलाह या तो एक नियमित अभिव्यक्ति को संकलित नहीं करती है, या उन्हें एक अलग विधानसभा के लिए पहले से संकलित करती है।

रेफरी: बीसीएल टीम ब्लॉग नियमित अभिव्यक्ति प्रदर्शन [डेविड गुटिएरेज़]



0

मुझे आशा है कि नीचे दिए गए कोड से आपको repile फ़ंक्शन की अवधारणा को समझने में मदद मिलेगी

import re

x="""101 COM    Computers
205 MAT   Mathematics
189 ENG   English
222 SCI Science
333 TA  Tamil
5555 KA  Kannada
6666  TL  Telugu
777777 FR French
"""

#compile reg expression / successfully compiled regex can be used in any regex 
#functions    
find_subject_code=re.compile("\d+",re.M)
#using compiled regex in regex function way - 1
out=find_subject_code.findall(x)
print(out)
#using compiled regex in regex function way - 2
out=re.findall(find_numbers,x)
print(out)

#few more eg:
#find subject name
find_subjectnames=re.compile("(\w+$)",re.M) 
out=find_subjectnames.findall(x)
print(out)


#find subject SHORT name
find_subject_short_names=re.compile("[A-Z]{2,3}",re.M) 
out=find_subject_short_names.findall(x)
print(out)

आपके उत्तर के लिए धन्यवाद, लेकिन आपका कोड पायथन भाषा में है। सवाल Microsoft .NET फ्रेमवर्क RegexOptions.Compiled विकल्प के बारे में था । आप प्रश्न के नीचे संलग्न [ .net ] टैग देख सकते हैं ।
पेट

जी हां! धन्यवाद पेटी
डैनियल मुथुपंडी १४'१
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.