gpt4 book ai didi

python - 如何获取 Python 解释器堆栈的当前深度?

转载 作者:太空狗 更新时间:2023-10-30 00:23:24 25 4
gpt4 key购买 nike

来自documentation :

sys.getrecursionlimit()

Return the current value of the recursion limit, the maximum depth of the Python interpreter stack. This limit prevents infinite recursion from causing an overflow of the C stack and crashing Python. It can be set by setrecursionlimit().

我目前在酸洗对象时达到递归限制。我正在 pickle 的对象只有几层嵌套,所以我对发生的事情有点困惑。

我已经能够通过以下 hack 来规避这个问题:

try:
return pickle.dumps(x)
except:
try:
recursionlimit = getrecursionlimit()
setrecursionlimit(2*recursionlimit)
dumped = pickle.dumps(x)
setrecursionlimit(recursionlimit)
return dumped
except:
raise

在不同的上下文中测试上述代码片段有时会导致第一次try 成功,有时会导致第二次try 成功。到目前为止,我还不能让它成为 raise 异常。

为了进一步调试我的问题,有一种方法可以获得堆栈的当前深度会很有帮助。这将使我能够验证进入的堆栈深度是否决定了上面的代码片段是否会在第一次 try 或第二次成功。

标准库有没有提供获取栈深度的函数,如果没有,如何获取?

def get_stack_depth():
# what goes here?

最佳答案

如果速度有问题,绕过检查模块会更快。

testing depth: 50 (CPython 3.7.3)
stacksize4b() | depth: 50 | 2.0 µs
stacksize4b(200) | depth: 50 | 2.2 µs
stacksize3a() | depth: 50 | 2.4 µs
stacksize2a() | depth: 50 | 2.9 µs
stackdepth2() | depth: 50 | 3.0 µs
stackdepth1() | depth: 50 | 3.0 µs
stackdepth3() | depth: 50 | 3.4 µs
stacksize1() | depth: 50 | 7.4 µs # deprecated
len(inspect.stack()) | depth: 50 | 1.9 ms

我将我的函数名称缩短为 stacksize(),为了更容易区分,我将 @lunixbochs 的函数称为 stackdepth()


基本算法:

对于小堆栈大小,这可能是代码简洁性、可读性和速度之间的最佳折衷。对于大约 10 帧以下,由于开销较低,只有 stackdepth1() 稍微快一些。

from itertools import count

def stack_size2a(size=2):
"""Get stack size for caller's frame.
"""
frame = sys._getframe(size)

for size in count(size):
frame = frame.f_back
if not frame:
return size

为了为更大的堆栈大小实现更好的时序,一些更精细的算法是可能的。stacksize3a() 将链式属性查找与来自 stackdepth1() 的近距离完成相结合,以获得更有利的计时斜率,开始获得大约 > 70 帧的 yield 我的基准。

from itertools import count

def stack_size3a(size=2):
"""Get stack size for caller's frame.
"""
frame = sys._getframe(size)
try:
for size in count(size, 8):
frame = frame.f_back.f_back.f_back.f_back.\
f_back.f_back.f_back.f_back
except AttributeError:
while frame:
frame = frame.f_back
size += 1
return size - 1

benchmark100

高级算法:

正如@lunixbochs 在回答中提出的那样,sys._getframe() 基本上是 C 代码中的 stackdepth1()。虽然更简单的算法总是从堆栈顶部的现有帧开始它们的深度搜索在 Python 中,向下检查堆栈以查找更多现有帧,stacksize4b() 允许启动通过其 stack_hint 参数从任何级别搜索,并且可以根据需要向下或向上搜索堆栈。

在幕后,调用 sys._getframe() 始终意味着从顶部框架向下遍历堆栈到指定深度。由于 Python 和 C 之间的性能差异如此巨大,如果有必要,在应用基本关闭之前多次调用 sys._getframe() 以找到更接近最深帧的帧仍然可以带来返回- 使用 frame.f_back 在 Python 中进行逐帧搜索。

from itertools import count

def stack_size4b(size_hint=8):
"""Get stack size for caller's frame.
"""
get_frame = sys._getframe
frame = None
try:
while True:
frame = get_frame(size_hint)
size_hint *= 2
except ValueError:
if frame:
size_hint //= 2
else:
while not frame:
size_hint = max(2, size_hint // 2)
try:
frame = get_frame(size_hint)
except ValueError:
continue

for size in count(size_hint):
frame = frame.f_back
if not frame:
return size

stacksize4b() 的使用理念是将大小提示置于预期堆栈深度的下限以实现快速启动,同时仍然能够应对每一个剧烈而短暂的情况- 堆栈深度的变化。

基准测试显示 stacksize4b(),默认 size_hint=8 并调整了 size_hint=200。对于基准测试,3-3000 范围内的所有堆栈深度都经过测试,以显示 stacksize4b() 时序中的特征锯齿模式。

benchmark300 benchmark3000

关于python - 如何获取 Python 解释器堆栈的当前深度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34115298/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com