2009-09-24 34 views
6

Tôi đang cố gắng sử dụng trình biên dịch Python để tăng tốc mã của tôi. Tôi đã có thể xác định chức năng cụ thể, nơi gần như toàn bộ thời gian được sử dụng, nhưng tôi không thể tìm ra vị trí của hàm đó trong thời gian đó.Hiểu đầu ra của hồ sơ Python

Dưới đây tôi có đầu ra hồ sơ, cho thấy "appendBallot" là thủ phạm chính và tiêu thụ gần 116 giây. Dưới đây, tôi có mã cho "appendBallot".

Tôi không thể tìm ra từ đầu ra hồ sơ, phần nào của "appendBallot" tôi cần tối ưu hóa khi mục nhập thời gian cao nhất tiếp theo ít hơn một giây. Tôi chắc rằng nhiều bạn có thể cho tôi biết từ mã của tôi, nhưng tôi muốn hiểu cách lấy thông tin đó từ đầu ra hồ sơ. Mọi sự trợ giúp sẽ rất được trân trọng.

hồ sơ đầu ra:

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) 

Code:

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

Nó thực sự là khẳng định() đó là hogging lên tất cả các thời gian. Tôi tự hỏi, nếu trình lược tả Python bỏ qua các câu lệnh khẳng định() vì chúng sẽ không được thực thi nếu mã được chạy với -O, –

+0

Cảm ơn tất cả các câu trả lời hữu ích. –

+0

Trình biên dịch Python không bỏ qua 'assert'/statements/nhiều hơn là bỏ qua tất cả các câu lệnh/câu lệnh khác/trong phương thức. Viết 'assert (expression)' thay vì chỉ 'biểu thức khẳng định' không biến nó thành một lời gọi hàm có thể được bỏ qua. –

Trả lời

3

Trình đơn có thể giống như vậy. Phương pháp tôi sử dụng là this. Nó được quyền đến trung tâm của vấn đề trong thời gian không.

+0

Mặc dù có nhiều nhận xét hay nhưng đây là câu trả lời nhanh nhất và dễ nhất cho những gì tôi cần. –

+0

@Jeff. Tôi rất vui vì nó đã giúp. –

+0

@George: Tôi biết ý bạn là gì, nhưng nó hơi lớn. Nếu liên kết chết, tôi sẽ giải quyết nó. –

6

Vâng tôi đi qua đó cùng một vấn đề là tốt.

Cách duy nhất tôi biết để giải quyết vấn đề này là bọc chức năng lớn của bạn vào một số cuộc gọi chức năng nhỏ hơn. Điều này sẽ cho phép trình lược tả tính đến từng cuộc gọi hàm nhỏ hơn.

Thú vị đủ, quá trình làm điều này (đối với tôi, dù sao) đã làm cho nó rõ ràng, nơi không hiệu quả, vì vậy tôi thậm chí không phải chạy profiler.

+0

Bạn đang đúng (theo nghĩa thực tế) và chưa "viết lại mã của bạn một cách khác nhau để sự thiếu hụt của profiler là ít rõ ràng" có vẻ như câu trả lời sai. – Basic

5

Tôi đã xem mã của bạn và có vẻ như bạn thực hiện rất nhiều cuộc gọi chức năng và tra cứu thuộc tính như một phần của 'kiểm tra' hoặc nhìn trước khi nhảy. Bạn cũng có nhiều mã dành riêng để theo dõi cùng một điều kiện, tức là nhiều bit mã đang xem xét việc tạo ID duy nhất.

thay vì cố gắng gán một số loại chuỗi duy nhất cho mỗi lá phiếu, có thể bạn không chỉ cần sử dụng ballotID (một số nguyên?)

bây giờ bạn có thể có một cuốn từ điển (uniqueBallotIDs) lập bản đồ ballotID và đối tượng lá phiếu thực tế.

quá trình này có thể là một cái gì đó như thế này:

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) 

Bạn có thể có khả năng xử lý một số lo lắng của bạn về từ điển thiếu một phím được bằng cách sử dụng một defaultdict (từ các mô-đun bộ sưu tập). collection docs

Sửa cho đầy đủ, tôi sẽ bao gồm việc sử dụng mẫu của 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

Tôi đã sử dụng this decorator trong mã của tôi, và nó giúp tôi với công việc pyparsing chỉnh của tôi.

+0

Điều này có vẻ tốt. – Fragsworth

3

Tôi sẽ hỗ trợ Fragsworth bằng cách nói rằng bạn sẽ muốn chia nhỏ chức năng của mình thành các phần nhỏ hơn.

Có nói rằng, bạn đang đọc đầu ra chính xác: thời gian tottime là thứ để xem.

Bây giờ cho nơi chậm lại của bạn có khả năng là:

Vì có vẻ là 100000 cuộc gọi đến appendBallot, và không có bất kỳ vòng rõ ràng, tôi muốn đề nghị đó là trong khẳng định của bạn. Vì bạn đang thực hiện:

assert(ballotID not in self.ballotIDs) 

Điều này thực sự sẽ hoạt động như một vòng lặp. Do đó, lần đầu tiên bạn gọi hàm này, nó sẽ lặp qua một mảng (có thể trống), và sau đó xác nhận xem giá trị đã được tìm thấy chưa. Thời gian 100000 lần nó sẽ lặp qua toàn bộ mảng.

Và có một lỗi có thể xảy ra ở đây: nếu lá phiếu bị xóa, thì lá phiếu tiếp theo được thêm vào sẽ có cùng id như lá phiếu được thêm vào cuối cùng (trừ khi đó là lá phiếu bị xóa). Tôi nghĩ bạn nên sử dụng một bộ đếm đơn giản hơn. Bằng cách đó bạn chỉ có thể tăng nó mỗi khi bạn thêm một lá phiếu. Ngoài ra, bạn có thể sử dụng UUID để nhận id duy nhất.

Hoặc, nếu bạn đang xem xét mức độ kiên trì nào đó, hãy sử dụng ORM và làm cho nó hoạt động tạo ID và kiểm tra duy nhất cho bạn.

+0

Anh ấy không "gọi" bất cứ điều gì; khẳng định là một tuyên bố. –

+0

Tệ của tôi. Sẽ sửa chữa. –

2

Bạn có hai vấn đề trong lát này ít mã:

# 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) 

Đầu tiên nó xuất hiện mà self.ballotIDs là một danh sách, do đó tuyên bố khẳng định sẽ gây ra hành vi bậc hai. Vì bạn không cung cấp bất kỳ tài liệu nào cho cấu trúc dữ liệu của mình, nên không thể mô tả được, nhưng nếu thứ tự xuất hiện không quan trọng, bạn có thể sử dụng tập hợp thay vì danh sách.

Thứ hai, logic (trong trường hợp không tài liệu về những gì một ballotID là tất cả về, và những gì một không-Không ballotID arg nghĩa) dường như nghe trộm nghiêm túc:

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

Nhận xét khác:

Thay vì adict.has_key(key), hãy sử dụng key in adict - nó nhanh hơn và trông đẹp hơn.

Bạn có thể xem xét xem xét cấu trúc dữ liệu của mình ... chúng có vẻ hơi baroque; có thể có một chút thời gian của CPU liên quan đến việc xây dựng chúng.

Các vấn đề liên quan