最后一天,解决另一个Project Euler我在管理 big for i in range(n)
循环时遇到了麻烦。
我观察到 python
会抛出不同的错误,取决于 x
变量有多大。
这是一个mcve示例:
for i in range(x):
pass
地点:
如果
x = 10**20
我得到一个OverflowError
, 确切地说:OverflowError:range()结果有太多项目
。否则如果
x = 10**15
我收到MemoryError
。else if
x = 10**9
我遇到了instant-system-freeze
,我必须硬重置我的电脑。很少情况下,我的电脑不但没有卡住,反而填满了大约 5GB 的交换空间,变得非常慢。
我试图理解 python built-in exception 的含义:
-
Raised when the result of an arithmetic operation is too large to be represented. This cannot occur for long integers [...] and for most operations with plain integers, which return a long integer instead. [...]
这意味着整数永远不应该抛出此异常;此异常的原因是
range()
包含太多项目,因此我认为10**15
也会抛出相同的异常,但我得到了不同的异常。 .. -
Raised when an operation runs out of memory but the situation may still be rescued (by deleting some objects). [...]
我应该删除哪个对象来挽救这种情况?它只是退出,所以情况无法挽救......
如果感觉
ram
使用量过多,为什么它会以10**9
卡住我的电脑?
最后,我的问题是:
为什么我会得到 3 个不同的结果,仅取决于 x
变量中存储的值?
注意:
最佳答案
好吧,range
尝试构建一个整个列表,其中包含与 x
一样多的项目。
对于死亡即时交换情况,您可以估计,假设 64 位和固定的 8 字节整数,x = 10**9
大约值 8 Go。因此,如果您没有更多的内存(考虑到已经使用的 RAM),您就可以明白为什么系统需要交换。
再往下看,如果函数无法分配足够大的 block 来保存结果(在 10**15
的情况下),则可能会引发 MemoryError
看起来很大)。
我不知道 range
的实现细节,但它可能使用 OverflowError
来确保元素的绝对最大数量(也许以某种方式以防止 MemoryError
,基于实际可用内存)。
正如 @ShadowRanger 的评论中提到的,如果结果的长度无法容纳 size_t
变量(2**31
),则会引发 OverflowError
> (32 位)或 2**63
(64 位)),因为它无法初始化这样的列表。
正如您所提到的,xrange 不存在此问题,因为它不会生成整个列表,而是在每次迭代时生成一个值。这就是为什么迭代器/生成器具有内存效率。
<小时/>所以我快速浏览了一下,你可以看到 in the 2.7 source为什么它会抛出OverflowError
。
关于Python:MemoryError、OverflowError、即时系统卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33149842/