捕获并不昂贵,看起来相对较慢的部分是堆栈跟踪本身的创建以及如果需要随后展开堆栈。
我所知道的所有允许您捕获堆栈跟踪的基于堆栈的语言都需要执行这些操作。
- 当
raise 被调用时收集堆栈信息。请注意,Java 1.7 允许您抑制堆栈收集,而且速度更快,但您会丢失很多有用的信息。语言没有明智的方法知道谁会捕获它,因此忽略异常无济于事,因为无论如何它必须执行大部分工作。
- 如果我们引发异常,则展开堆栈,即释放所有内存并展开,直到我们遇到有效的捕获。
与上述两个操作相比,catch 是微不足道的。这里有一些代码可以证明随着堆栈深度的增加,性能会下降。
#!/usr/bin/env python
import os
import re
import time
import pytest
max_depth = 10
time_start = [0] * (max_depth + 1)
time_stop = [0] * (max_depth + 1)
time_total = [0] * (max_depth + 1)
depth = []
for x in range(0, max_depth):
depth.append(x)
@pytest.mark.parametrize('i', depth)
def test_stack(benchmark, i):
benchmark.pedantic(catcher2, args=(i,i), rounds=10, iterations=1000)
#@pytest.mark.parametrize('d', depth)
#def test_recursion(benchmark, d):
# benchmark.pedantic(catcher, args=(d,), rounds=50, iterations=50)
def catcher(i, depth):
try:
ping(i, depth)
except Exception:
time_total[depth] += time.clock() - time_start[depth]
def recurse(i, depth):
if(d > 0):
recurse(--i, depth)
thrower(depth)
def catcher2(i, depth):
global time_total
global time_start
try:
ping(i, depth)
except Exception:
time_total[depth] += time.clock() - time_start[depth]
def thrower(depth):
global time_start
time_start[depth] = time.clock()
raise Exception('wtf')
def ping(i, depth):
if(i < 1): thrower(i, depth)
return pong(i, depth)
def pong(i, depth):
if(i < 0): thrower(i,depth)
return ping(i - 4, depth)
if __name__ == "__main__":
rounds = 200000
class_time = 0
class_start = time.clock()
for round in range(0, rounds):
ex = Exception()
class_time = time.clock() - class_start
print("%d ex = Exception()'s %f" % (rounds, class_time))
for depth in range(0, max_depth):
#print("Depth %d" % depth)
for round in range(0, rounds):
catcher(depth, depth)
for rep in range(0, max_depth):
print("depth=%d time=%f" % (rep, time_total[rep]/1000000))
输出是,调用Exception()的时间(时间是相对的)
200000 ex = Exception()'s 0.040469
depth=0 time=0.103843
depth=1 time=0.246050
depth=2 time=0.401459
depth=3 time=0.565742
depth=4 time=0.736362
depth=5 time=0.921993
depth=6 time=1.102257
depth=7 time=1.278089
depth=8 time=1.463500
depth=9 time=1.657082
比我更擅长 Python 的人也许可以让 py.test 在最后打印时间。
注意,几周前有一个与 Java 非常相似的问题。无论使用何种语言,这都是一个非常有用的线程......
Which part of throwing an Exception is expensive?