2011-06-02 16 views
12

पर पुन: प्रयास करने के लिए सबसे प्रभावी तरीका मैं दो फाइलों के माध्यम से जाने के लिए एक पायथन स्क्रिप्ट पर काम कर रहा हूं - जिसमें यूयूआईडी की एक सूची है, जिसमें बड़ी संख्या में लॉग प्रविष्टियां हैं - प्रत्येक पंक्ति जिसमें अन्य फाइलों में से यूयूआईडी शामिल है। कार्यक्रम का उद्देश्य फ़ाइल 1 से यूयूआईडीएस की एक सूची बनाना है, फिर प्रत्येक बार जब यूयूआईडी लॉग फ़ाइल में पाया जाता है, तो मैच मिलने पर प्रत्येक बार संबंधित मान को बढ़ाएं।पाइथन में एक बड़ी फ़ाइल (10 जीबी +)

इतनी लंबी कहानी कम है, गिनती है कि लॉग फ़ाइल में प्रत्येक यूयूआईडी कितनी बार प्रकट होता है। फिलहाल, मेरे पास एक सूची है जो यूयूआईडी के साथ कुंजी के रूप में आबादी है, और मूल्य के रूप में 'हिट' है। फिर एक और लूप जो लॉग फ़ाइल की प्रत्येक पंक्ति पर पुनरावृत्त करता है, और जांच करता है कि लॉग में यूयूआईडी यूयूआईडी सूची में यूयूआईडी से मेल खाता है या नहीं। यदि यह मेल खाता है, तो यह मूल्य में वृद्धि करता है।

for i, logLine in enumerate(logHandle):   #start matching UUID entries in log file to UUID from rulebase 
     if logFunc.progress(lineCount, logSize): #check progress 
      print logFunc.progress(lineCount, logSize) #print progress in 10% intervals 
     for uid in uidHits: 
      if logLine.count(uid) == 1:    #for each UUID, check the current line of the log for a match in the UUID list 
       uidHits[uid] += 1     #if matched, increment the relevant value in the uidHits list 
       break        #as we've already found the match, don't process the rest 
     lineCount += 1    

यह काम करता है जैसा कि यह करना चाहिए - लेकिन मुझे यकीन है कि फ़ाइल को संसाधित करने का एक और अधिक प्रभावी तरीका है। मैं कुछ गाइडों के माध्यम से रहा हूं और पाया है कि 'गणना' का उपयोग एक संकलित रेगेक्स का उपयोग करने से तेज है। मैंने सोचा कि रेखा से लाइन के बजाए हिस्सों में फ़ाइलों को पढ़ने से डिस्क I/O समय की मात्रा को कम करके प्रदर्शन में सुधार होगा, लेकिन परीक्षण फ़ाइल ~ 200 एमबी पर प्रदर्शन अंतर नगण्य था। अगर किसी के पास कोई अन्य तरीका है तो मैं बहुत आभारी रहूंगा :)

+2

फ़ाइल I/O आमतौर पर आपके द्वारा पढ़े गए हिस्सों के आकार के बावजूद बफर किया जाता है। – delnan

+3

क्या इसे और अधिक कुशल होने की आवश्यकता है? इसमें कितना समय लगता है? आपको इसे कब तक लेने की आवश्यकता है? हो सकता है कि आप पहले से ही अपने स्टोरेज (डिस्क) की प्रदर्शन सीमा को हिट कर चुके हों, इस मामले में इससे कोई फर्क नहीं पड़ता कि आपकी पाइथन लिपि कितनी तेज है। –

+0

यह अब एक परीक्षण फ़ाइल के माध्यम से चल रहा है - यह 10 जीबी फ़ाइल के माध्यम से आधे रास्ते है और इसे लगभग 30 मिनट लिया जाता है। मेरा पहला पायथन आउट होने के नाते मुझे वास्तव में पता नहीं है कि यह तेज़ या धीमा है या नहीं। X मिनट में इसे पूरा करने के लिए कोई आवश्यकता नहीं है, लेकिन तेज़ बेहतर है;) – SG84

उत्तर

14

कार्यात्मक रूप से सोचें!

  1. एक ऐसा फ़ंक्शन लिखें जो लॉग फ़ाइल की एक पंक्ति लेगा और यूयूआईडी वापस करेगा। इसे uuid पर कॉल करें, कहें।

  2. लॉग फ़ाइल की प्रत्येक पंक्ति में इस फ़ंक्शन को लागू करें। यदि आप पायथन 3 का उपयोग कर रहे हैं तो आप अंतर्निहित फ़ंक्शन मानचित्र का उपयोग कर सकते हैं; अन्यथा, आपको itertools.imap का उपयोग करने की आवश्यकता है।

  3. इस इटरेटर को संग्रह में पास करें। काउंटर।

    collections.Counter(map(uuid, open("log.txt"))) 
    

यह काफी बेहतर कुशल हो जाएगा।

एक जोड़े की टिप्पणियां:

  • यह पूरी तरह से UUIDs की सूची पर ध्यान न देकर केवल वे जो लॉग फ़ाइल में प्रदर्शित गिना जाता है। यदि आप इसे नहीं चाहते हैं तो आपको प्रोग्राम को कुछ हद तक संशोधित करने की आवश्यकता होगी।

    • आपका कोड धीमा है क्योंकि आप गलत डेटा संरचनाओं का उपयोग कर रहे हैं। एक नियम वह है जो आप यहां चाहते हैं।
+0

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

+5

@ एसजी 84 आप पाइथन के जेनरेटर http://www.dabeaz.com/generators/Generators.pdf पर विशेष रूप से बड़ी फ़ाइल को प्रोसेस करने के लिए एक उत्कृष्ट लेख देख सकते हैं। आप प्रबुद्ध हो जाएंगे :-) – OnesimusUnbound

+0

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

3

आप mincemeat.py की कोशिश की है? यह MapReduce वितरित कंप्यूटिंग ढांचे का एक पायथन कार्यान्वयन है। मुझे यकीन नहीं है कि आपके पास प्रदर्शन लाभ होगा क्योंकि मैंने अभी तक इसका उपयोग करने से पहले 10 जीबी डेटा संसाधित नहीं किया है, हालांकि आप इस ढांचे का पता लगा सकते हैं।

3

यह आपके प्रश्न का 5-लाइन का जवाब नहीं है, लेकिन PyCon'08 पर Generator Tricks for System Programmers नामक एक उत्कृष्ट ट्यूटोरियल था। A Curious Course on Coroutines and Concurrency नामक फ़ॉलोअप ट्यूटोरियल भी है।

जनरेटर ट्यूटोरियल विशेष रूप से इसके उदाहरण के रूप में बड़ी लॉग फ़ाइल प्रसंस्करण का उपयोग करता है।

4

उपरोक्त लोगों की तरह, 10 जीबी फ़ाइल के साथ आप शायद अपनी डिस्क की सीमाओं को बहुत जल्दी हिट करेंगे। कोड-केवल सुधारों के लिए, जेनरेटर सलाह बहुत अच्छी है। अजगर 2.x में यह

uuid_generator = (line.split(SPLIT_CHAR)[UUID_FIELD] for line in file) 

की तरह कुछ ऐसा लगता है कि यह वास्तव में एक अजगर समस्या होने की जरूरत नहीं है पर ध्यान देंगे। यदि आप यूयूआईडी की गणना करने से कहीं अधिक जटिल नहीं कर रहे हैं, तो यूनिक्स पाइथन कैन की तुलना में आपकी समस्याओं को तेज़ी से हल करने में सक्षम हो सकता है।

cut -d${SPLIT_CHAR} -f${UUID_FIELD} log_file.txt | sort | uniq -c 
0

मापने जहां ज्यादातर समय, खर्च किया जाता है एक प्रोफाइलर http://docs.python.org/library/profile.html

कहाँ सबसे अच्छा आपके डेटा की प्रकृति पर निर्भर करेगा अनुकूलन करने के लिए उपयोग करने का प्रयास: अगर UUIDs की सूची नहीं बहुत लंबा है, आप पा सकते उदाहरण के लिए, "अगर लॉगफन। प्रगति (लाइनकाउंट, लॉग आकार)" पर एक बड़ा हिस्सा खर्च किया जाता है। यदि सूची बहुत लंबी है, तो आप uidHits.keys() के परिणाम को लूप के बाहर एक चर के लिए सहेजने में मदद कर सकते हैं और इसके बजाय शब्दकोश की बजाय इसे फिर से चालू कर सकते हैं, लेकिन रोश ऑक्सिमोरॉन ने आईडी को ढूंढने का सुझाव दिया है और फिर इसके लिए जांच कर रहा है uidHits शायद और भी मदद करेगा।

किसी भी मामले में, आप lineCount चर को खत्म कर सकते हैं, और इसके बजाय i का उपयोग कर सकते हैं। और find(uid) != -1count(uid) == 1 से बेहतर हो सकता है यदि रेखाएं बहुत लंबी हैं।

संबंधित मुद्दे