当前位置:  开发笔记 > 编程语言 > 正文

为什么Python在尝试计算非常大的数字时会"先发制人"地挂起?

如何解决《为什么Python在尝试计算非常大的数字时会"先发制人"地挂起?》经验,为你挑选了2个好方法。

关于杀死使用过多内存的进程之前我已经问过这个问题,而且我已经解决了大部分问题.

然而,有一个问题:计算大量数字似乎不受我试图使用的方法的影响.下面的代码旨在为进程设置10秒的CPU时间限制.

import resource
import os
import signal

def timeRanOut(n, stack):
    raise SystemExit('ran out of time!')
signal.signal(signal.SIGXCPU, timeRanOut)

soft,hard = resource.getrlimit(resource.RLIMIT_CPU)
print(soft,hard)
resource.setrlimit(resource.RLIMIT_CPU, (10, 100))

y = 10**(10**10)

希望在运行此脚本(在Unix机器上)时看到的是:

-1 -1
ran out of time!

相反,我没有输出.我获得输出的唯一方法是使用Ctrl+ C,如果我在10秒后Ctrl+ 我得到这个C:

^C-1 -1
ran out of time!
CPU time limit exceeded

如果I Ctrl+ C 10秒之前,那么我必须做两次,并且控制台输出如下所示:

^C-1 -1
^CTraceback (most recent call last):
  File "procLimitTest.py", line 18, in 
    y = 10**(10**10)
KeyboardInterrupt

在试验和尝试解决这个问题的过程中,我还介绍time.sleep(2)了打印和大数计算.它似乎没有任何影响.如果我y = 10**(10**10)改为y = 10**10,则print和sleep语句按预期工作.添加flush=True到print语句或print语句sys.stdout.flush()之后也不起作用.

为什么我不能限制计算非常大数的CPU时间?我该如何修复或至少减轻这种影响?


附加信息:

Python版本: 3.3.5 (default, Jul 22 2014, 18:16:02) \n[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)]

Linux信息: Linux web455.webfaction.com 2.6.32-431.29.2.el6.x86_64 #1 SMP Tue Sep 9 21:36:05 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux



1> El'endia Sta..:

TLDR: Python预先计算代码中的常量.如果使用至少一个中间步骤计算任何非常大的数字,则该过程是CPU时间限制的.


花了相当多的搜索,但我已经发现的证据表明,Python 3中,它评估任何东西之前发现代码中的预计算常量文字.其中之一是这个网页:Python的Peephole Optimizer.我在下面引用了一些内容.

ConstantExpressionEvaluator

该类预先计算了许多常量表达式,并将它们存储在函数的常量列表中,包括明显的二进制和一元操作以及仅由常量组成的元组.特别值得注意的是,复杂的文字不是由编译器表示为常量而是表达式,因此2 + 3j表示为

LOAD_CONST n (2) LOAD_CONST m (3j) BINARY_ADD

这个类将它们转换为

LOAD_CONST q (2+3j)

这可以为使用复杂常量的代码带来相当大的性能提升.

2+3j作为一个例子的事实非常强烈地表明,不仅小的常量被预先计算和缓存,而且代码中的任何常量文字也是如此.我还发现了另一个Stack Overflow问题的评论(在Python中缓存了常量计算吗?):

请注意,对于Python 3,窥孔优化器预先计算1/3常量.(特别是CPython.) - Mark Dickinson 10月7日19:40

这些都得到了替换这一事实的支持

y = 10**(10**10)

与此挂起,即使我永远不会调用的功能!

def f():
    y = 10**(10**10)

好消息

幸运的是,我的代码中没有任何这样巨大的文字常量.此类常量的任何计算都将在以后发生,这可能会受到CPU时间限制的限制.我变了

y = 10**(10**10)

对此,

x = 10
print(x)
y = 10**x
print(y)
z = 10**y
print(z)

并根据需要获得此输出!

-1 -1
10
10000000000
ran out of time!

这个故事的寓意是:限制由CPU时间和内存消耗(或其他方式)的过程将工作,如果没有在Python中试图预先计算代码的大型常量.


有趣(对我而言)在Windows 7 64Bit py 2.6.6上它开始使用多个核心.

2> 小智..:

使用功能.

看起来Python似乎试图预先计算整数文字(我只有经验证据;如果有人有来源请告诉我).这通常是一种有用的优化,因为脚本中的绝大多数文字可能小到足以在预计算时不会出现明显的延迟.要解决这个问题,您需要使您的文字成为非常量计算的结果,例如带参数的函数调用.

例:

import resource
import os
import signal

def timeRanOut(n, stack):
    raise SystemExit('ran out of time!')
signal.signal(signal.SIGXCPU, timeRanOut)

soft,hard = resource.getrlimit(resource.RLIMIT_CPU)
print(soft,hard)
resource.setrlimit(resource.RLIMIT_CPU, (10, 100))

f = lambda x=10:x**(x**x)
y = f()

这给出了预期的结果:

xubuntu@xubuntu-VirtualBox:~/Desktop$ time python3 hang.py
-1 -1
ran out of time!

real    0m10.027s
user    0m10.005s
sys     0m0.016s

推荐阅读
罗文彬2502852027
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有