论坛首页 编程语言技术论坛

python异常处理对性能影响怎么样?

浏览 6594 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-01-19   最后修改:2011-01-19

一、糟糕的代码

在使用python编程语言处理查找列表或字典中的某个数据项时,我经常看到这样的代码(省略具体逻辑):

场景一:
try:
    data_list = find("condition")[0]
except:
    pass

场景二:
try:
    dict_list = find("condition")["key"]
except:
    pass

 以上这些代码虽然能够满足程序的功能,但这都不是最佳的实现方式,原因如下:
1、try捕获异常会造成异常(软中断),会影响性能。
2、作为靠谱的程序员,应该采取防御性的方式编码,而不应该将错误的处理都丢给系统。

二、糟糕的代码执行时间上的PK

基于上述原因,我与编码者(上述代码作者)交流过,其中的回答“python对异常的处理方式非常好,从而几乎不影响性能,这也是推荐的一种处理方式”让我好奇,于是做了个小实验---python异常处理对性能的有多大的影响?源代码如下:

#! /bin/usr/env python
# -*- coding:utf-8 -*-

import time

#统计方法执行的时间
def count_time(func):
    def wrap(*args):
        start = time.time()
        func(*args)
        end = time.time()
        print "func:%s  time:(%0.3f ms)" % (func.func_name, (end-start) * 1000)
    return wrap

#key不存在的时候
@count_time
def not_exists_use_try(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["not_exists"]
        except:
            pass

#key存在的时候
@count_time
def exists_use_try(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["do_something"]
        except:
            pass

#key不存在的时候并使用Exception
@count_time
def not_exists_use_try_except(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["not_exists"]
        except Exception, e:
            pass

#key存在的时候并使用Exception
@count_time
def exists_use_try_except(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["do_something"]
        except Exception, e:
            pass

#使用防御性编码
@count_time
def not_use_try(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        if "not_exists" in dict_list :
            pass
        else:
            pass

def run(max):
    print "max:%s" % max
    not_exists_use_try(max)
    not_exists_use_try_except(max)
    exists_use_try(max)
    exists_use_try_except(max)
    not_use_try(max)

if __name__ == "__main__":
#100
    run(100)
#1,000
    run(1000)
#10,000
    run(10000)
#100,000
    run(100000)
#1,000,000
    run(1000000)
#10,000,000
    run(10000000)

 通过对上面的实验程序的3次运行,采样结果如下:

max:100
func:not_exists_use_try  time:(0.110 ms)
func:not_exists_use_try_except  time:(0.110 ms)
func:exists_use_try  time:(0.012 ms)
func:exists_use_try_except  time:(0.011 ms)
func:not_use_try  time:(0.009 ms)

max:1,000
func:not_exists_use_try  time:(0.941 ms)
func:not_exists_use_try_except  time:(1.058 ms)
func:exists_use_try  time:(0.091 ms)
func:exists_use_try_except  time:(0.091 ms)
func:not_use_try  time:(0.063 ms)

max:10,000
func:not_exists_use_try  time:(10.341 ms)
func:not_exists_use_try_except  time:(10.869 ms)
func:exists_use_try  time:(0.879 ms)
func:exists_use_try_except  time:(0.904 ms)
func:not_use_try  time:(0.616 ms)

max:100,000
func:not_exists_use_try  time:(95.245 ms)
func:not_exists_use_try_except  time:(109.051 ms)
func:exists_use_try  time:(9.277 ms)
func:exists_use_try_except  time:(9.290 ms)
func:not_use_try  time:(7.086 ms)

max:1,000,000
func:not_exists_use_try  time:(932.254 ms)
func:not_exists_use_try_except  time:(1088.768 ms)
func:exists_use_try  time:(110.238 ms)
func:exists_use_try_except  time:(104.085 ms)
func:not_use_try  time:(85.284 ms)

max:10,000,000
func:not_exists_use_try  time:(9292.667 ms)
func:not_exists_use_try_except  time:(10858.698 ms)
func:exists_use_try  time:(1037.037 ms)
func:exists_use_try_except  time:(1008.167 ms)
func:not_use_try  time:(812.829 ms)

 观察上面的采样结果得知:
一、程序执行时间随着执行的次数同比递增增长。
二、其中使用try...except,Exception的方式会比使用try...except的方式稍花时间,但这点时间可以忽略不计。
三、其中当使用try方式时发生异常比使用try方式时无异常花费时间约10倍。
四、使用防御性方式编码在这几种方式中最花费时间最少。

三、总结

以上数据会根据程序执行环境的不同而得出不同的采样结果,从上面的采样数据结果来看,执行次数在10,000,000级别时候才有明显的延时,抛开性能影 响的层面,作为靠谱的程序员,应该采取防御性的方式编码,而不应该将错误的处理都丢给系统,这样的好处明显就是性能的提升,同时也加强了程序的可读性。

   发表时间:2011-01-19  
你的测试不公平,你应当至少还加上一种测试情况:
@count_time
def exists_not_use_try(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        if "do_something" in dict_list :
            dict_list["do_something"]
        else:
            pass

这里做了两次判断,在我的机器上,它比exists_use_try和exists_use_try_except都慢。

从性能上来说,如果key存在的情况是大多数情况,用try except可能速度更快。

其实速度根本相差无几,可读性才重要。在python中,另一种方法是使用get。我也同意你的观点,应当使用防御性编程,可能是因为我之前是写java的,在java中创建异常会同时创建stacktrace,这是很耗时的操作,在python中异常是不带stacktrace(在python中叫做traceback)的,所以创建异常的开销比java中小很多。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics