2010-10-14 33 views
20

Tôi đã tự hỏi tại sao thử-trừ là chậm hơn so với nếu trong chương trình dưới đây.Python nếu so với try-except

def tryway(): 
    try: 
     while True: 
      alist.pop() 
    except IndexError: 
     pass 

def ifway(): 
    while True: 
     if alist == []: 
      break 
     else: 
      alist.pop() 
if __name__=='__main__': 
    from timeit import Timer 
    alist = range(1000) 
    print "Testing Try" 
    tr = Timer("tryway()","from __main__ import tryway") 
    print tr.timeit() 
    print "Testing If" 
    ir = Timer("ifway()","from __main__ import ifway") 
    print ir.timeit() 

Kết quả tôi nhận được thật thú vị.

Testing Try 
2.91111302376 
Testing If 
0.30621099472 

Bất kỳ ai cũng có thể giải thích lý do vì sao quá chậm?

+2

Nó không thực sự áp dụng ở đây, nhưng đôi khi nhìn vào 'dis.dis (funcname)' là tiện dụng để tìm ra chính xác cách thức hoạt động bên trong – Daenyth

Trả lời

38

Bạn đang đặt chỉ sử dụng một lần. Cuộc gọi đầu tiên tới "tryway" sẽ xóa cuộc gọi, sau đó mọi cuộc gọi liên tiếp đều không thực hiện được gì.

def tryway(): 
    alist = range(1000) 
    try: 
     while True: 
      alist.pop() 
    except IndexError: 
     pass 

def ifway(): 
    alist = range(1000) 
    while True: 
     if alist == []: 
      break 
     else: 
      alist.pop() 
if __name__=='__main__': 
    from timeit import Timer 
    print "Testing Try" 
    tr = Timer("tryway()","from __main__ import tryway") 
    print tr.timeit(10000) 
    print "Testing If" 
    ir = Timer("ifway()","from __main__ import ifway") 
    print ir.timeit(10000) 

>>> Testing Try 
>>> 2.09539294243 
>>> Testing If 
>>> 2.84440898895 
+4

Cảm ơn bây giờ tôi cảm thấy như một thằng ngốc: | – James

+42

James, nếu chúng ta không có gì để học và không bao giờ mắc sai lầm ngớ ngẩn, sẽ không có lý do gì cho StackOverflow. – msw

0

Không chắc chắn nhưng tôi nghĩ rằng nó là một cái gì đó như thế này: trong khi thực sự làm theo các dòng lệnh bình thường có nghĩa là bộ vi xử lý có thể đường ống và làm tất cả các loại điều tốt đẹp. Các ngoại lệ nhảy thẳng qua tất cả những thứ đó để VM cần xử lý nó một cách đặc biệt và cần có thời gian.

+0

Cách tôi nhìn nó là khi nó tự sát ngoại trừ nó chỉ kiểm tra ở cuối và sau đó kết thúc. Trong khi đó nếu cái nhìn là kiểm tra danh sách 1000 lần mà tôi nghĩ sẽ chậm hơn .... – James

+0

Tôi nghĩ rằng so sánh với danh sách trống là khá nhanh, vì vậy nó không mất nhiều thời gian làm việc đó. Lưu ý, tôi không chắc chắn về những điều này, chỉ nghĩ rằng tôi muốn cung cấp cho bạn dòng suy nghĩ của tôi. – dutt

4

Xử lý ngoại lệ thường chậm trong hầu hết các ngôn ngữ. Hầu hết các trình biên dịch, thông dịch viên và máy ảo (có hỗ trợ xử lý ngoại lệ) xử lý các ngoại lệ (thành ngữ ngôn ngữ) là ngoại lệ (không phổ biến). Tối ưu hóa hiệu suất liên quan đến sự cân bằng và làm cho các ngoại lệ nhanh chóng thường có nghĩa là các khu vực khác của ngôn ngữ sẽ bị ảnh hưởng (dù ở hiệu suất hay sự đơn giản của thiết kế). Ở mức độ kỹ thuật hơn, ngoại lệ thường có nghĩa là VM/interpretter (hoặc thư viện thực thi thời gian chạy) phải lưu một loạt trạng thái và bắt đầu kéo tất cả trạng thái trên ngăn xếp cuộc gọi hàm (được gọi là thư giãn) cho đến khi điểm bắt giữ hợp lệ (ngoại trừ).

Hoặc nhìn nó từ một quan điểm khác, chương trình ngừng chạy khi một ngoại lệ xảy ra và "trình gỡ lỗi" chiếm ưu thế. Trình gỡ lỗi này tìm kiếm trở lại thông qua ngăn xếp (gọi hàm dữ liệu) cho một bắt khớp với ngoại lệ. Nếu nó tìm thấy một, nó dọn dẹp mọi thứ và trả về điều khiển cho chương trình tại thời điểm đó. Nếu nó không tìm thấy nó thì nó sẽ trả về quyền kiểm soát cho người dùng (có lẽ dưới dạng một trình gỡ rối tương tác hoặc REPL của Python).

+4

Điều này là khá off-topic trong bối cảnh của python. Các ngoại lệ trong python thực sự rẻ, và nếu trường hợp không đặc biệt nó phổ biến hơn ngoại lệ (như nó phải là), thì nó sẽ rẻ hơn để thử/nắm bắt hơn kiểm tra - như được xác minh trong câu trả lời của Glenn. EAFP> LBYL. – Daenyth

3

Nếu bạn thực sự quan tâm đến tốc độ, cả hai thí sinh của bạn có thể làm với việc giảm cân.

while True: chậm hơn while 1: - True là "biến" toàn cầu được tải và kiểm tra; 1 là một hằng số và trình biên dịch thực hiện phép thử và phát ra một bước nhảy vô điều kiện.

while True: là dự phòng trong ifway. Gấp trong khi/nếu/đột với nhau: while alist != []:

while alist != []: là một cách chậm viết while alist:

Hãy thử điều này:

def tryway2(): 
    alist = range(1000) 
    try: 
     while 1: 
      alist.pop() 
    except IndexError: 
     pass 

def ifway2(): 
    alist = range(1000) 
    while alist: 
     alist.pop() 

'

+4

Trong khi nhận xét của bạn về 'True' là đúng trong ngữ cảnh của py 2.x, trong py3k nó là một từ khóa thực và không có chi phí trên. – Daenyth

2

Vẫn iterating là cách nhanh hơn với cho, mặc dù đôi khi chúng tôi muốn danh sách để thể chất shirink vì vậy chúng tôi biết có bao nhiêu là trái. Sau đó, alist nên được tham số cho máy phát điện. (John cũng đúng cho while alist:) Tôi đặt chức năng làm máy phát và danh sách được sử dụng (ifway()), v.v.nên các giá trị được actualy sử dụng ra khỏi chức năng (thậm chí không sử dụng):

def tryway(): 
    alist = range(1000) 
    try: 
     while True: 
      yield alist.pop() 
    except IndexError: 
     pass 

def whileway(): 
    alist = range(1000) 
    while alist: 
     yield alist.pop() 

def forway(): 
    alist = range(1000) 
    for item in alist: 
     yield item 

if __name__=='__main__': 
    from timeit import Timer 
    print "Testing Try" 
    tr = Timer("list(tryway())","from __main__ import tryway") 
    print tr.timeit(10000) 
    print "Testing while" 
    ir = Timer("list(whileway())","from __main__ import whileway") 
    print ir.timeit(10000) 
    print "Testing for" 
    ir = Timer("list(forway())","from __main__ import forway") 
    print ir.timeit(10000) 

J:\test>speedtest4.py 
Testing Try 
6.52174983133 
Testing while 
5.08004508953 
Testing for 
2.14167694497 
+0

Mặc dù kết quả của bạn cho thấy 'try' là một chút chậm hơn 'while', thử nghiệm của tôi với Python 3 đã cho tôi như sau:' Testing Hãy thử 1,0719404926951281 Kiểm tra trong khi 1,2370897208711098 Testing cho 0.00439965737' (Tôi chỉ cần thêm parantheses để in báo cáo và thay đổi 'phạm vi (1000)' để 'danh sách (phạm vi (1000))'.) – AXO

-1

chương trình phòng thủ đòi hỏi rằng một thử nghiệm cho điều kiện đó là rất hiếm và/hoặc bất thường, một số trong đó trong suốt quá trình một năm hoặc nhiều năm sẽ không xảy ra, do đó trong những trường hợp này có lẽ thử - ngoại trừ có thể được biện minh.

+0

Đó là một câu trả lời rất khó hiểu và không rõ ràng. vui lòng làm rõ. – Difster

0

Chỉ cần nghĩ đến quăng này vào trộn: Tôi đã thử các kịch bản sau đây mà dường như cho thấy rằng xử lý một ngoại lệ là chậm hơn so với xử lý một tuyên bố else:

import time 

n = 10000000 
l = range(0, n) 
t0 = time.time() 
for i in l: 
    try: 
     i[0] 
    except: 
     pass 
t1 = time.time() 
for i in l: 
    if type(i) == list(): 
     print(i) 
    else: 
     pass 
t2 = time.time() 
print(t1-t0) 
print(t2-t1) 

cung cấp cho:

5.5908801555633545 
3.512694835662842 

Vì vậy, (mặc dù tôi biết ai đó có thể sẽ nhận xét về việc sử dụng time thay vì timeit), có vẻ chậm hơn 60% khi sử dụng try/except in loops. Vì vậy, có lẽ tốt hơn để đi với if/else khi đi qua một vòng lặp cho vài tỷ mục.

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