为什么IDLE 3.4在这个程序上需要这么长时间?

时间:2014-06-14 04:47:20

标签: python python-idle python-3.4

编辑:我完全重做了这个问题。该问题与time.time()

无关

这是一个程序:

import time
start=time.time()
a=9<<(1<<26)             # The line that makes it take a while
print(time.time()-start)

当程序保存为文件并在Python 3.4中使用IDLE运行时,大约需要10秒,即使0.0是从time.time()打印出来的。 IDLE非常清楚这个问题,因为当从命令行运行时,这个程序几乎没有时间。

另一个与senshin相同的具有相同效果的程序是:

def f(): 
    a = 9<<(1<<26)

我已经确认,当在Python 2.7 IDLE或python 2.7或3.4上的命令行中运行时,这个程序几乎是即时的。

那么Python 3.4 IDLE做了什么让它需要这么长时间?我知道计算这个数字并将其保存到内存是磁盘密集型的,但我想知道的是为什么Python 3.4 IDLE执行这个计算并在Python 2.7 IDLE和命令行Python可能没有时写入。

2 个答案:

答案 0 :(得分:1)

我会看那条线并把它拆开。你有:

9 << (1 << 26)

(1 << 26)是第一个被评估的表达式,它产生一个非常大的数字。这句话的意思是,你要将数字1加2乘以26的幂,有效地在内存中产生数字2 ** 26。然而,这不是问题。然后你将9向左移动2 ** 26.这会在内存中产生一个大约5000万位数的数字(我甚至无法计算它!),因为左移是太大了。将来要小心,因为看起来很小的变化实际上会变得非常快。如果它更大,你的程序可能根本没有运行。如果您感到好奇,您的表达式将以数学方式评估为9 * 2 ** (2 ** 26)

评论部分的模糊性可能实际上是关于如何通过引擎盖下的python处理这个巨大的内存部分,而不是IDLE。

编辑1:

我认为正在发生的事情是,数学表达式会评估其答案,即使被放置在尚未调用的函数内部,仅在表达式为自足时。这意味着如果在等式中使用变量,则等式将在字节代码中不受影响,并且在硬执行之前不进行评估。必须解释该函数,并且在该过程中,我认为您的值实际上是计算的,导致较慢的时间。我不确定这一点,但我强烈怀疑这种行为是根本原因。即使不是这样,你必须承认9<<(1<<26)将计算机踢到后面,没有太多的优化可以在那里完成。

In[73]: def create_number():
            return 9<<(1<<26)
In[74]: #Note that this seems instantaneous, but try calling the function!
In[75]: %timeit create_number()
#Python environment crashes because task is too hard

然而,在这种测试中存在轻微的欺骗行为。当我用常规时间尝试这个时,我得到了:

In[3]: from timeit import timeit
In[4]: timeit(setup = 'from __main__ import create_number', stmt = 'create_number()', number = 1)
Out[4]: .004942887388800443

另外请记住,打印值是不可行的,例如:

In[102]: 9<<(1<<26)

甚至不应该尝试。

获得更多支持:

我觉得自己像个反叛者,所以我决定看看如果我计算出等式的原始执行时会发生什么:

In[107]: %timeit 9<<(1<<26)
10000000 loops, best of 3: 22.8 ns per loop

In[108]: def empty(): pass
In[109]: %timeit empty()
10000000 loops, best of 3: 96.3 ns per loop

这真的很可疑,因为显然这个计算比Python调用空函数的时间要快得多,显然情况并非如此。我再说一遍,这不是即时的,但可能与在内存中某处检索已计算的对象有关,并重用该值来计算表达式。无论如何,好问题。

答案 1 :(得分:0)

我真的很困惑。以下是3.4.1的更多结果。在3.4.1或3.3.5中从编辑器运行前两行中的任何一行都会产生相同的对比度。

>>> a = 1 << 26; b = 9 << a  # fast, , .5 sec
>>> c = 9 << (1 << 26)  # slow, about 3 sec
>>> b == c  # fast
True
>>> exec('d=9<<(1<<26)', globals())  # fast
>>> c == d  # fast
True

正常执行和闲置之间的区别在于,如上所述,在exec调用中空闲exec的代码,除了&#39;全局&#39;传递给exec不是globals()而是配置为看起来像globals()的dict。在这方面我不知道任何2.7 - 3.4的空闲差异,除了执行人员从执行到执行的变更。如何执行exec比单个执行官更快?如何更快地添加中间绑定?