2009-09-24 13 views
6

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

नीचे मेरे पास प्रोफ़ाइल आउटपुट है, जो दिखाता है कि "एपेंडबॉलॉट" प्राथमिक अपराधी है और लगभग 116 सेकंड का उपभोग करता है। नीचे, मेरे पास "appendBallot" के लिए कोड है।

मैं प्रोफ़ाइल आउटपुट से नहीं समझ सकता, "एपेंडबॉलॉट" का कौन सा हिस्सा मुझे अनुकूलित करने की आवश्यकता है क्योंकि अगली उच्चतम समय प्रविष्टि एक सेकंड से भी कम है। मुझे यकीन है कि आप में से कई मुझे सिर्फ मेरे कोड से बता सकते हैं, लेकिन मैं समझना चाहता हूं कि प्रोफ़ाइल आउटपुट से उस जानकारी को कैसे प्राप्त किया जाए। किसी भी तरह की सहायता का स्वागत किया जाएगा।

प्रोफ़ाइल उत्पादन:

ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 116.168 116.168 <string>:1(<module>) 
     1 0.001 0.001 116.168 116.168 {execfile} 
     1 0.003 0.003 116.167 116.167 foo.py:1(<module>) 
     1 0.000 0.000 116.139 116.139 ballots.py:330(loadKnown) 
     1 0.000 0.000 116.109 116.109 plugins.py:148(load) 
     1 0.196 0.196 116.108 116.108 BltBallotLoader.py:37(loadFile) 
    100000 114.937 0.001 115.912 0.001 ballots.py:133(appendBallot) 
    100000 0.480 0.000 0.790 0.000 ballots.py:117(newBallot) 
    316668 0.227 0.000 0.310 0.000 ballots.py:107(getNumCandidates) 
417310/417273 0.111 0.000 0.111 0.000 {len} 
    200510 0.071 0.000 0.071 0.000 {method 'append' of 'list' objects} 
    99996 0.045 0.000 0.045 0.000 {method 'add' of 'set' objects} 
    100000 0.042 0.000 0.042 0.000 {method 'has_key' of 'dict' objects} 
     1 0.000 0.000 0.030 0.030 plugins.py:202(getLoaderPluginClasses) 
     1 0.000 0.000 0.030 0.030 plugins.py:179(getPluginClasses) 
     1 0.000 0.000 0.030 0.030 plugins.py:205(getLoaderPluginClass) 
     3 0.016 0.005 0.029 0.010 {__import__} 
     1 0.022 0.022 0.025 0.025 ballots.py:1(<module>) 
     1 0.010 0.010 0.013 0.013 BltBallotLoader.py:1(<module>) 
     7 0.000 0.000 0.003 0.000 re.py:227(_compile) 

कोड:

def appendBallot(self, ballot, ballotID=None): 
    "Append a ballot to this Ballots object." 

    # String representation of ballot for determining whether ballot is unique 
    ballotString = str(list(ballot)) 

    # Ballot as the appropriate array to conserve memory 
    ballot = self.newBallot(ballot) 

    # Assign a ballot ID if one has not been given 
    if ballotID is None: 
     ballotID = len(self.ballotIDs) 
    assert(ballotID not in self.ballotIDs) 
    self.ballotIDs.append(ballotID) 

    # Check to see if we have seen this ballot before 
    if self.uniqueBallotsLookup.has_key(ballotString): 
     i = self.uniqueBallotsLookup[ballotString] 
     self.uniqueBallotIDs[i].add(ballotID) 
    else: 
     i = len(self.uniqueBallots) 
     self.uniqueBallotsLookup[ballotString] = i 
     self.uniqueBallots.append(ballot) 
     self.uniqueBallotIDs.append(set([ballotID])) 
    self.ballotOrder.append(i) 
+0

यह वास्तव में जोरदार() है जो हर समय घूम रहा है। मुझे आश्चर्य है कि पाइथन प्रोफाइलर जोरदार() कथनों को अनदेखा करता है क्योंकि कोड को ओओ, –

+0

के साथ चलाने के लिए निष्पादित नहीं किया जाएगा, सभी सहायक उत्तरों के लिए धन्यवाद। –

+0

पायथन प्रोफाइलर विधि में सभी अन्य/कथन/अनदेखा करने की तुलना में 'जोर'/कथन/किसी और को अनदेखा नहीं कर रहा है। केवल 'अभिव्यक्ति अभिव्यक्ति' के बजाय 'जोर दें (अभिव्यक्ति)' लिखना इसे फ़ंक्शन कॉल में नहीं बदलता है जिसे अनगिनत किया जा सकता है। –

उत्तर

3

प्रोफाइलर ऐसा हो सकते हैं। मैं जिस विधि का उपयोग करता हूं वह this है। यह किसी भी समय समस्या के दिल के लिए सही हो जाता है।

+0

हालांकि बहुत अच्छी टिप्पणियां थीं, यह वही है जो मुझे आवश्यकतानुसार सबसे तेज़ और आसान उत्तर प्रदान करता था। –

+0

@ जेफ। मुझे खुशी है कि यह मदद की। –

+0

@ जॉर्ज: मुझे पता है कि आपका क्या मतलब है, लेकिन यह थोड़ा बड़ा है। अगर लिंक मर जाता है, तो मैं इससे निपटूंगा। –

6

हाँ मुझे लगता है कि एक ही समस्या भर में रूप में अच्छी तरह से आया था।

एकमात्र तरीका यह है कि मैं इस बारे में काम करने के बारे में जानता हूं, अपने बड़े फ़ंक्शन को कई छोटी फ़ंक्शन कॉल में लपेटना है। यह प्रोफाइलर को प्रत्येक छोटी फ़ंक्शन कॉल को ध्यान में रखेगा।

दिलचस्प दिलचस्प, यह करने की प्रक्रिया (मेरे लिए, वैसे भी) ने यह स्पष्ट किया कि अक्षमताएं थीं, इसलिए मुझे प्रोफाइलर चलाने की भी आवश्यकता नहीं थी।

+0

आप सही (व्यावहारिक अर्थ में) हैं और फिर भी "अपने कोड को अलग-अलग लिखते हैं ताकि प्रोफाइलर की कमियां कम स्पष्ट हों" गलत जवाब की तरह लगती है। – Basic

5

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

बजाय प्रत्येक मतदान के लिए अद्वितीय स्ट्रिंग के कुछ प्रकार असाइन करने की कोशिश की

, तो आप सिर्फ ballotID उपयोग नहीं कर सका (एक पूर्णांक संख्या?)

अब आप एक शब्दकोश (uniqueBallotIDs) मानचित्रण ballotID और हो सकता था वास्तविक मतपत्र वस्तु।

प्रक्रिया कुछ इस तरह हो सकता है:

def appendBallot(self, ballot, ballotID=None): 
    if ballotID is None: 
     ballotID = self._getuniqueid() # maybe just has a counter? up to you. 
    # check to see if we have seen this ballot before. 
    if not self._isunique(ballotID): 
     # code for non-unique ballot ids. 
    else: 
     # code for unique ballot ids. 

    self.ballotOrder.append(i) 

आप (संग्रह मॉड्यूल से) एक defaultdict का उपयोग करके लापता किसी कुंजी के शब्दकोश के बारे में अपनी चिंताओं को में से कुछ को संभालने में सक्षम हो सकता है। collection docs

संपादित संपूर्णता के लिए मैं defaultdict का एक नमूना उपयोग शामिल होंगे:

>>> from collections import defaultdict    

>>> ballotIDmap = defaultdict(list) 
>>> ballotID, ballot = 1, object() # some nominal ballotID and object. 
>>> # I will now try to save my ballotID. 
>>> ballotIDmap[ballotID].append(ballot) 
>>> ballotIDmap.items() 
[(1, [<object object at 0x009BB950>])] 
4

मैं अपने कोड में this decorator का इस्तेमाल किया है, और यह मुझे मेरे pyparsing ट्यूनिंग काम के साथ मदद की।

+0

यह अच्छा लग रहा है। – Fragsworth

3

मैं फ्रैग्सवर्थ का समर्थन करके यह कहकर समर्थन करूंगा कि आप अपने कार्य को छोटे से विभाजित करना चाहते हैं।

ऐसा कहकर, आप आउटपुट को सही तरीके से पढ़ रहे हैं: टेटीम देखने वाला एक है।

जहाँ आपके मंदी होने की संभावना है के लिए अब:

चूंकि appendBallot को 100000 कॉल होने लगते हैं, और वहाँ किसी भी स्पष्ट छोरों नहीं हैं, मेरा सुझाव था यह आपके दर्शाते हैं उनमें है। चूंकि आप निष्पादित कर रहे हैं:

assert(ballotID not in self.ballotIDs) 

यह वास्तव में एक लूप के रूप में कार्य करेगा। इस प्रकार, पहली बार जब आप इस फ़ंक्शन को कॉल करते हैं, तो यह एक (संभवतः खाली) सरणी के माध्यम से फिर से शुरू हो जाएगा, और फिर मान लें कि मान क्या मिला था। 100000 वें समय यह पूरे सरणी के माध्यम से फिर से शुरू होगा।

और वास्तव में यहां एक संभावित बग है: यदि कोई मतपत्र हटा दिया जाता है, तो अगला मतपत्र जोड़ा गया अंतिम आईडी के रूप में एक ही आईडी होगा (जब तक वह हटाया नहीं जाता)। मुझे लगता है कि आप एक साधारण काउंटर का उपयोग करना बेहतर होगा। इस तरह आप प्रत्येक बार जब आप मतपत्र जोड़ते हैं तो इसे बढ़ा सकते हैं। वैकल्पिक रूप से, आप अद्वितीय आईडी प्राप्त करने के लिए यूयूआईडी का उपयोग कर सकते हैं।

वैकल्पिक रूप से, यदि आप दृढ़ता के कुछ स्तर को देख रहे हैं, तो ओआरएम का उपयोग करें, और इसे आईडी पीढ़ी करने के लिए प्राप्त करें, और आपके लिए अद्वितीय जांच करें।

# Assign a ballot ID if one has not been given 
if ballotID is None: 
    ballotID = len(self.ballotIDs) 
assert(ballotID not in self.ballotIDs) 
self.ballotIDs.append(ballotID) 

सबसे पहले ऐसा लगता है कि self.ballotIDs एक सूची है, इसलिए ज़ोर बयान द्विघात व्यवहार का कारण होगा:

+0

वह कुछ भी "कॉलिंग" नहीं कर रहा है; जोर देना एक बयान है। –

+0

मेरा बुरा। ठीक कर देंगे। –

2

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

obj.appendBallot(ballota, 2) # self.ballotIDs -> [2] 
obj.appendBallot(ballotb) # self.ballotIDs -> [2, 1] 
obj.appendBallot(ballotc) # wants to add 2 but triggers assertion 

अन्य टिप्पणियां:

दूसरे, तर्क (प्रलेखन के अभाव में एक ballotID सब के बारे में क्या है पर, और क्या एक नहीं कोई नहीं ballotID आर्ग का मतलब है) गंभीरता से bugged लगता है adict.has_key(key) के बजाय, key in adict का उपयोग करें - यह तेज़ है और बेहतर दिखता है।

आप अपने डेटा संरचनाओं की समीक्षा करने पर विचार करना चाहेंगे ... वे थोड़ा बारोक लगते हैं; उन्हें बनाने में शामिल CPU समय का एक उचित हिस्सा हो सकता है।

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