我试图重复IPython%time的功能,但由于某些奇怪的原因,测试某些功能的结果是可怕的。
IPython的:
In [11]: from random import shuffle
....: import numpy as np
....: def numpy_seq_el_rank(seq, el):
....: return sum(seq < el)
....:
....: seq = np.array(xrange(10000))
....: shuffle(seq)
....:
In [12]: %timeit numpy_seq_el_rank(seq, 10000//2)
10000 loops, best of 3: 46.1 µs per loop
的Python:
from timeit import timeit, repeat
def my_timeit(code, setup, rep, loops):
result = repeat(code, setup=setup, repeat=rep, number=loops)
return '%d loops, best of %d: %0.9f sec per loop'%(loops, rep, min(result))
np_setup = '''
from random import shuffle
import numpy as np
def numpy_seq_el_rank(seq, el):
return sum(seq < el)
seq = np.array(xrange(10000))
shuffle(seq)
'''
np_code = 'numpy_seq_el_rank(seq, 10000//2)'
print 'Numpy seq_el_rank:\n\t%s'%my_timeit(code=np_code, setup=np_setup, rep=3, loops=100)
及其输出:
Numpy seq_el_rank:
100 loops, best of 3: 1.655324947 sec per loop
正如你所看到的,在python中我创建了100个循环而不是10000(并且得到慢于35000倍的结果),就像在ipython中一样,因为它需要很长时间。任何人都可以解释为什么python中的结果如此缓慢?
UPD:
这是cProfile.run('my_timeit(code=np_code, setup=np_setup, rep=3, loops=10000)')
输出:
30650 function calls in 4.987 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 4.987 4.987 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 <timeit-src>:2(<module>)
3 0.001 0.000 4.985 1.662 <timeit-src>:2(inner)
300 0.006 0.000 4.961 0.017 <timeit-src>:7(numpy_seq_el_rank)
1 0.000 0.000 4.987 4.987 Lab10.py:47(my_timeit)
3 0.019 0.006 0.021 0.007 random.py:277(shuffle)
1 0.000 0.000 0.002 0.002 timeit.py:121(__init__)
3 0.000 0.000 4.985 1.662 timeit.py:185(timeit)
1 0.000 0.000 4.985 4.985 timeit.py:208(repeat)
1 0.000 0.000 4.987 4.987 timeit.py:239(repeat)
2 0.000 0.000 0.000 0.000 timeit.py:90(reindent)
3 0.002 0.001 0.002 0.001 {compile}
3 0.000 0.000 0.000 0.000 {gc.disable}
3 0.000 0.000 0.000 0.000 {gc.enable}
3 0.000 0.000 0.000 0.000 {gc.isenabled}
1 0.000 0.000 0.000 0.000 {globals}
3 0.000 0.000 0.000 0.000 {isinstance}
3 0.000 0.000 0.000 0.000 {len}
3 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
29997 0.001 0.000 0.001 0.000 {method 'random' of '_random.Random' objects}
2 0.000 0.000 0.000 0.000 {method 'replace' of 'str' objects}
1 0.000 0.000 0.000 0.000 {min}
3 0.003 0.001 0.003 0.001 {numpy.core.multiarray.array}
1 0.000 0.000 0.000 0.000 {range}
300 4.955 0.017 4.955 0.017 {sum}
6 0.000 0.000 0.000 0.000 {time.clock}
答案 0 :(得分:3)
嗯,有一个问题是你误读了结果。 ipython
告诉您10,000次迭代中每次迭代花费多长时间,总时间最短。 timeit.repeat
模块报告了整轮100次迭代所花费的时间(再次,最短的三次)。因此,真正的差异是每个循环(ipython)为46.1μs,而每个循环(python)为16.5 ms,仍然是差异的350倍,但不是35,000x。
您没有显示ipython
的分析结果。您的ipython
会话中是否可能from numpy import sum
或from numpy import *
?如果是这样的话,那么您的numpy.sum
(针对numpy
数组进行了优化,并run several orders of magnitude faster}进行了优化,而python
代码(隔离了全局数据) ipython
没有运行正常sum
的方式(必须将所有值转换为Python int
并将它们相加)。
如果您检查分析输出,几乎所有工作都在sum
完成;如果你的代码中的那部分加快了几个数量级,那么总时间也会同样减少。这可以解释“真实”的差异;在上面链接的测试用例中,它是一个40倍的差异,这是一个较小的数组(数组越小,numpy
可以“炫耀”越少)具有更复杂的值(相对于0和1的总和)我相信。)
其余部分(如果有的话)可能是代码如何eval
略有不同的问题,或者可能是random
shuffle的奇怪问题(对于一致的测试,你想要播种random
使用一致的种子使“随机性”可重复)但我怀疑这是一个超过百分之几的差异。
答案 1 :(得分:1)
在python的一个实现中,此代码运行速度可能比另一个更慢。一个可以与另一个不同地进行优化,可以预编译某些部分而另一个部分被完全解释。找出原因的唯一方法是分析您的代码。
https://docs.python.org/2/library/profile.html
import cProfile
cProfile.run('repeat(code, setup=setup, repeat=rep, number=loops)')
会给出类似于
的结果ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 <stdin>:1(testing)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.000 0.000 0.000 0.000 {method 'upper' of 'str' objects}
在显示功能调用,制作完成次数以及拍摄时间时,会显示。