2013-02-11 23 views
6

मैं एक सी # एप्लिकेशन लिख रहा हूं जो कई नियमित अभिव्यक्तियों (~ 10) को तारों (~ 25 मिलियन) तारों पर चलाता है। मैंने इसे Google पर करने का प्रयास किया था, लेकिन "धीमा" के साथ रेगेक्स के लिए कोई भी खोज ट्यूटोरियल से भरी हुई है कि कैसे बैकफ्रेंसिंग इत्यादि रेगेक्स को धीमा कर देती है। मुझे लगता है कि यह मेरी समस्या नहीं है क्योंकि मेरे regexes तेजी से शुरू और धीमा हो जाता है।regex प्रदर्शन

पहले लाख या तो तारों के लिए नियमित अभिव्यक्तियों को चलाने के लिए प्रति 1000 तारों में लगभग 60ms लगते हैं। अंत में, यह उस बिंदु तक धीमा हो गया है जहां इसकी 600 मिलीमीटर लग रही है। क्या किसी को पता है क्यों?

यह बदतर था, लेकिन मैंने कैश किए गए संस्करण के बजाय RegEx के उदाहरणों का उपयोग करके और अभिव्यक्तियों को संकलित करके इसे बेहतर बना दिया।

मेरे कुछ regexes को अलग-अलग होना आवश्यक है उदा। उपयोगकर्ता का नाम के आधार पर यह हो सकता है mike said (\w*) या john said (\w*)

मेरे समझ है कि यह संभव उन regexes संकलन और मानकों में पारित करने के लिए नहीं है (उदाहरण, saidRegex.Match(inputString, userName))।

क्या किसी के पास कोई सुझाव है?

-

+6

क्या आप कुछ कोड पोस्ट कर सकते हैं? –

+0

यदि आप प्रदर्शन में सुधार के लिए सामान्य उपाय किए हैं तो अधिक सलाह देना बहुत मुश्किल है। यदि यह ठीक है, तो क्या आप अपना रेगेक्स दिखा सकते हैं? – nhahtdh

+17

यह असंभव है कि रेगेक्स इंजन स्वयं धीमा हो रहा है। अधिक संभावना है कि आपका एप्लिकेशन परिणाम सहेज रहा है, इसलिए स्मृति बढ़ रही है, और यह समग्र प्रदर्शन को कम करने का कारण बन रहा है। अपनी प्रक्रिया मेमोरी आकार की निगरानी करें। मेमोरी लीक के लिए भी जाँच करें। – Barmar

उत्तर

2

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

डेटाबेस डेटा में मिलान किए गए डेटा को विभाजित करने के बाद डेटा को एक बार पार्स करें। ऐसा लगता है कि आप निम्नलिखित क्षेत्रों पर कब्जा करने की कोशिश कर रहे हैं लग रहा है: - यह पार्स

Player_Name | Monetary_Value 

आप प्रति पंक्ति इन मूल्यों से युक्त एक डेटाबेस तालिका बनाने के लिए थे, तो और उसके बाद प्रत्येक नई पंक्ति को पकड़ने के रूप में यह बनाया जा रहा है - और डेटा टेबल में संलग्न करें - आप आसानी से डेटा के खिलाफ किसी प्रकार का विश्लेषण/गणना कर सकते हैं - 25 एम पंक्तियों को बार-बार पार्स किए बिना (जो एक अपशिष्ट है)।

इसके अतिरिक्त - पहले रन पर, यदि आप 25 एम रिकॉर्ड्स को 100,000 रिकॉर्ड ब्लॉक में तोड़ना चाहते थे, तो एल्गोरिदम 250 बार (100,000 x 250 = 25,000,000) चलाएं - आप जिस प्रदर्शन का वर्णन कर रहे हैं उसका आनंद ले सकते हैं कोई धीमा नहीं, क्योंकि आप नौकरी को तोड़ रहे हैं।

दूसरे शब्दों में - निम्नलिखित पर विचार:

  1. एक डेटाबेस तालिका बनाएँ इस प्रकार है:

    CREATE TABLE PlayerActions (
        RowID   INT PRIMARY KEY IDENTITY, 
        Player_Name VARCHAR(50) NOT NULL, 
        Monetary_Value MONEY  NOT NULL 
    ) 
    
  2. एक एल्गोरिथ्म है कि अपने 25 मी पंक्तियों 100k टुकड़ों में टूट जाती है बनाएँ। एक अनुमान के रूप में LINQ/EF5 का उपयोग कर उदाहरण।

    public void ParseFullDataSet(IEnumerable<String> dataSource) { 
        var rowCount = dataSource.Count(); 
        var setCount = Math.Floor(rowCount/100000) + 1; 
    
        if (rowCount % 100000 != 0) 
         setCount++; 
    
        for (int i = 0; i < setCount; i++) { 
         var set = dataSource.Skip(i * 100000).Take(100000); 
         ParseSet(set); 
        } 
    } 
    
    public void ParseSet(IEnumerable<String> dataSource) { 
        String playerName = String.Empty; 
        decimal monetaryValue = 0.0m; 
    
        // Assume here that the method reflects your RegEx generator. 
        String regex = RegexFactory.Generate(); 
    
        for (String data in dataSource) { 
         Match match = Regex.Match(data, regex); 
         if (match.Success) { 
          playerName = match.Groups[1].Value; 
    
          // Might want to add error handling here. 
          monetaryValue = Convert.ToDecimal(match.Groups[2].Value); 
    
          db.PlayerActions.Add(new PlayerAction() { 
           // ID = ..., // Set at DB layer using Auto_Increment 
           Player_Name = playerName, 
           Monetary_Value = monetaryValue 
          }); 
          db.SaveChanges(); 
    
          // If not using Entity Framework, use another method to insert 
          // a row to your database table. 
         } 
        } 
    } 
    
  3. ऊपर एक लोड अपने पूर्व मौजूदा डेटा के सभी पाने के लिए बार चलाएं।

  4. एक हुक किसी ऐसे स्थान जो आप एक नई पंक्ति के अलावा पता लगाने के लिए अनुमति देता है बनाएँ।हर बार एक नई पंक्ति बनाई है, फोन:

    ParseSet(new List<String>() { newValue }); 
    

    या गुणकों एक ही बार में बनाई गई हैं, तो कॉल:

    ParseSet(newValues); // Where newValues is an IEnumerable<String> 
    

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

+0

नोट: उपर्युक्त कोड संकलित किए बिना लिखा गया था - इसलिए मैं गारंटी नहीं देता कि यह काम करता है, लेकिन यह आपको आगे ले जाना चाहिए सही दिशा, यदि आप वर्णित समाधान को लागू करना चुनते हैं। –

+1

मेरे हिस्से पर थोड़ा देर हो चुकी है, लेकिन बहुत बहुत धन्यवाद! – mike1952

0

रेगेक्स को गणना करने में समय लगता है। हालांकि, यू कुछ चाल का उपयोग करके इसे कॉम्पैक्ट बना सकता है। रेगेक्स फ़ंक्शन से बचने के लिए आप सी # में स्ट्रिंग फ़ंक्शंस का भी उपयोग कर सकते हैं।

कोड लंबा होगा लेकिन प्रदर्शन में सुधार हो सकता है। स्ट्रिंग में वर्णों को काटने और निकालने के लिए कई फ़ंक्शन हैं और आपको आवश्यकतानुसार पैटर्न मिलान करना है। जैसे उदाहरण: इंडेऑफनी, लास्टइंडेक्सऑफ, इसमें शामिल हैं ....

string str= "mon"; 
string[] str2= new string[] {"mon","tue","wed"}; 

if(str2.IndexOfAny(str) >= 0) 
{ 
    //success code// 
}