【问题标题】:Does python have nested exception protection?python有嵌套异常保护吗?
【发布时间】:2018-08-30 14:34:01
【问题描述】:

考虑以下代码:

def printlen(x): print(len(x))

def argslist(x): return list(x.args)

def add(value_error, arg): raise Exception(*value_error, *arg)

def fibonacci(a, b, x):
    try:
        assert b<x
        printlen(b)
        try:
            add(a,b)
        except Exception as e:
            fibonacci(argslist(e), a, x)
    except AssertionError as e:
        print(e)

threshold = 1000
fibonacci([[]],[[]],[[]]*threshold)

代码使用 deftryexceptraise 打印出从 1 到阈值的斐波那契数两个特殊功能。 如果您删除“assert b threshold 设置为一个非常大的数字,python.exe 将接管 RAM 并冻结所有内容。 是否存在限制嵌套 raises、trys 和 excepts 的机制,或者只是阻止分配这么多内存?

【问题讨论】:

  • 肯定有嵌套异常处理;在这里查看答案:stackoverflow.com/questions/19883531/…
  • @gerowam 我在问是否有一种机制可以防止过多的嵌套。
  • 啊——类似于异常展开,但具有基于堆栈的递归。我猜不是(正如下面的答案所暗示的那样),因为 Python 被解释并且解释器不知道递归的深度。您可能会遇到递归深度限制,而不是内存不足。也许?
  • @gerowam 递归深度是运行时的事情,因此它与“解释”与“编译”无关。被编译或解释也不是语言的属性,而是来自语言实现(有 C 解释器 FWIW)。最后,CPython(参考实现)被编译成字节码,所以说它是“解释的”并不完全准确......

标签: python python-3.x


【解决方案1】:

将接管 RAM

从技术上讲,这是不可能的。

RAM 是指物理内存,python.exe 无法访问物理 RAM。 Windows 中的可执行文件只能访问virtual memory (MSDN)。 RAM 中实际有多少是由 Windows 决定的。

对于 32 位 Python,这应该不是什么大问题,因为它最多只能访问 4 GB。但是对于 64 位,它当然会开始使用页面文件并写入磁盘,这会使事情变慢。这甚至会影响其他程序。详情见memory limits (MSDN)

冻结一切

另外,几乎不可能,因为 Python 不能独占访问 CPU。一种称为抢占的机制将确保 Windows 可以将 CPU 分配给其他东西。

您发布的代码既不使用多线程也不使用多处理,因此它只使用 1 个 CPU。如果你有一个单核机器,那当然是 100%。在我的机器上,它只有 25%,其他一切都继续顺利运行:

是否有一种机制可以限制嵌套的 raise、try 和 excepts

我不这么认为。

或者只是阻止分配这么多内存?

是的,Windows 中有一种称为“Job (MSDN)”的机制可以做到这一点。您需要在具有内存配额的作业中运行 Python.exe。有一个 Superuser question 建议为此提供工具。

作为替代方案,您当然可以实现一个内存限制条件以使斐波那契数列停止,如下所示:

import os
import psutil
process = psutil.Process(os.getpid())
ram = psutil.virtual_memory().total
ram_limit = 70 / 100 * ram

[...]

if process.memory_info().private > ram_limit:
    assert False

出于调试原因,我使用了if,因此我可以在断言上放置一个断点来制作以下屏幕截图。

如您所见,私有字节(进程使用的内存)约为 23.5 GB,工作集(适合计算机物理 RAM 的内存)也约为 23.5 GB。到目前为止没有性能问题。

【讨论】:

  • 有办法限制递归次数,sys.setrecursopnlimit docs.python.org/2/library/sys.html#sys.setrecursionlimit
  • @ChristianSauer:是的,但几乎不适用,因为它既不会限制 RAM 也不会限制 CPU。获得可预测的结果也不可靠,因为这不是 fibunacci 函数的递归计数,而是所有堆栈帧的递归。有些方法是递归的,但不是很深。
  • 感谢您的回答!条件已经存在:断言 b
【解决方案2】:

不,没有这样的机制。 Python 会尽可能分配内存。当它变得不可能时,它会引发MemoryError

【讨论】:

    猜你喜欢
    • 2019-01-13
    • 1970-01-01
    • 2010-09-23
    • 2014-06-03
    • 2014-10-27
    • 2017-01-28
    • 1970-01-01
    • 2019-06-17
    • 1970-01-01
    相关资源
    最近更新 更多