MATLAB比Python快吗(简单的小实验)
我读过这个()我发现它有很多假设 我在一台仍然运行Windows XP的旧电脑上做了这个小实验 在MATLAB R2010b中,我在命令窗口中复制并粘贴了以下代码:MATLAB比Python快吗(简单的小实验),python,matlab,performance-testing,Python,Matlab,Performance Testing,我读过这个()我发现它有很多假设 我在一台仍然运行Windows XP的旧电脑上做了这个小实验 在MATLAB R2010b中,我在命令窗口中复制并粘贴了以下代码: tic x = 0.23; for i = 1:100000000 x = 4 * x * (1 - x); end toc x 结果是: Elapsed time is 0.603583 seconds. x = 0.947347510922557 然后,我用以下脚本保存了一个py文件: import time
tic
x = 0.23;
for i = 1:100000000
x = 4 * x * (1 - x);
end
toc
x
结果是:
Elapsed time is 0.603583 seconds.
x =
0.947347510922557
然后,我用以下脚本保存了一个py
文件:
import time
t = time.time()
x = 0.23
for i in range(100000000): x = 4 * x * (1 - x)
elapsed = time.time() - t
print(elapsed)
print(x)
我按了F5,结果是
49.78125
0.9473475109225565
在MATLAB中,它花费了0.60秒;在Python中,它花费了49.78秒(永恒!!)
所以问题是:有没有一种简单的方法让Python和MATLAB一样快
特别是:如何更改我的py
脚本,使其运行速度与MATLAB一样快
更新 我在PyPy中尝试了相同的实验(复制和粘贴相同的代码,如上所述):它与以前一样在同一台机器上用1.0470001697540283秒完成 我用1e9循环重复了这些实验 MATLAB结果:
Elapsed time is 5.599789 seconds.
1.643573442831396e-004
PyPy
结果:
8.609999895095825
0.00016435734428313955
我还尝试了正常的while
循环,得到了类似的结果:
t = time.time()
x = 0.23
i = 0
while (i < 1000000000):
x = 4 * x * (1 - x)
i += 1
elapsed = time.time() - t
elapsed
x
过一会儿,我将尝试NumPy
。一个(受过一定教育的)猜测是python不会在您的代码上执行。这意味着MATLAB代码正在执行一个大型计算,而不是许多(!)较小的计算。这是使用PyPy而不是作为PyPy的CPython的主要原因
如果您使用的是Python2.X,那么您应该用
range
代替xrange
,因为range
(在Python2.X中)创建了一个要迭代的列表。首先,使用time
不是这样测试代码的好方法。但是让我们忽略这一点
当您的代码执行大量循环并在每次循环中重复非常类似的工作时,JIT将做得非常好。当代码每次都做完全相同的事情时,对于可以从循环中提取的常量值,它会做得更好。另一方面,CPython必须为每个循环迭代执行多个字节码,因此速度会很慢。从我的机器上的快速测试来看,CPython 3.4.1需要24.2秒,而PyPy 2.4.0/3.2.5需要0.0059秒 IronPython和Jython也是JIT编译的(尽管使用的是更通用的JVM和.NET JIT),因此对于这类工作,它们往往也比CPython更快
通过使用数组和向量操作而不是Python列表和循环,通常也可以在CPython本身中加速这样的工作。例如,以下代码需要0.011秒:
i = np.arange(10000000)
i[:] = 4 * x * (1-x)
当然,在这种情况下,我们显式地只计算一次值并复制10000000次。但我们可以强迫它一次又一次地进行实际计算,仍然只需要0.12秒:
i = np.zeros((10000000,))
i = 4 * (x+i) * (1-(x+i))
其他选项包括在中编写部分代码(编译为Python的C扩展)和使用,JIT在CPython中编译代码。对于这样的玩具程序,如果您只想优化一次24秒的过程,那么自动生成和编译C代码所花费的时间可能会超过运行C代码而不是Python代码所节省的时间。但在现实生活中的数值编程中,两者都非常有用。(两人都能很好地与NumPy合作。) 而且总是会有新的项目出现。Q:我如何更改我的
py
脚本,使其运行速度与MATLAB一样快?
由于已经为您提供了许多知识丰富的指导,让我添加我的两分钱(以及一些定量结果)
(同样地,我希望您能原谅跳过:假设一个更复杂的计算任务)
- 检查代码是否有任何可能的算法改进、值重用和寄存器/缓存友好安排(
numpy.asfortranarray()
等)
- 尽可能在numpy中使用矢量化代码执行/循环展开
- 对于代码的稳定部分,同样使用LLVM编译器
numba
- 仅在代码的最终级别上使用其他(JIT)编译器技巧(nogil=True,nopython=True),以避免常见的过早优化错误
可能的成就确实是巨大的:
初始代码样本取自FX arena(毫秒、微秒和(浪费的)纳秒确实很重要-检查50%的市场事件,您有远少于900毫秒的时间(端到端双向交易),而不是HFT…)来处理EMA(200,关闭)
-过去200 Gbps USD烛光/棒的非平凡指数移动平均数,约5200多行:
import numba
#@jit # 2015-06 @autojit deprecated
@numba.jit('f8[:](i8,f8[:])')
def numba_EMA_fromPrice( N_period, aPriceVECTOR ):
EMA = aPriceVECTOR.copy()
alf = 2. / ( N_period + 1 )
for aPTR in range( 1, EMA.shape[0] ):
EMA[aPTR] = EMA[aPTR-1] + alf * ( aPriceVECTOR[aPTR] - EMA[aPTR-1] )
return EMA
对于这个“经典”代码,仅仅是numba
编译步骤就比普通的python/numpy代码执行有了改进
21x下降到大约半毫秒
# 541L
# ___________vvvvv__________# !!! !!!
#@numba.jit( nogil = True ) # JIT w/o GIL-lock w/ multi-CORE ** WARNING: ThreadSafe / DataCoherency measures **
# aClk.start();numba_EMA_fromPrice_EFF_ALGO( 200, price_H4_CLOSE );aClk.stop()
# Out[126]: 149929L # JIT-compile-pass
# Out[127]: 284L # re-use 0.3 [ms] v/s 11.5 [ms] CPython
# Out[128]: 256L
从大约11499[美国](是的,从大约11500微秒到只有541[美国])
但是,如果您对算法更加谨慎,并重新设计它,以便更智能、更高效地使用资源,那么结果将更加丰硕
@numba.jit
def numba_EMA_fromPrice_EFF_ALGO( N_period, aPriceVECTOR ):
alfa = 2. / ( N_period + 1 )
coef = ( 1 - alfa )
EMA = aPriceVECTOR * alfa
EMA[1:]+= EMA[0:-1] * coef
return EMA
# aClk.start();numba_EMA_fromPrice_EFF_ALGO( 200, price_H4_CLOSE );aClk.stop()
# Out[112]: 160814L # JIT-compile-pass
# Out[113]: 331L # re-use 0.3 [ms] v/s 11.5 [ms] CPython
# Out[114]: 311L
# Out[115]: 324L
以及多CPU核心处理的最终抛光触摸
46x加速到大约四分之一毫秒
# 541L
# ___________vvvvv__________# !!! !!!
#@numba.jit( nogil = True ) # JIT w/o GIL-lock w/ multi-CORE ** WARNING: ThreadSafe / DataCoherency measures **
# aClk.start();numba_EMA_fromPrice_EFF_ALGO( 200, price_H4_CLOSE );aClk.stop()
# Out[126]: 149929L # JIT-compile-pass
# Out[127]: 284L # re-use 0.3 [ms] v/s 11.5 [ms] CPython
# Out[128]: 256L
作为最后的奖金。更快有时并不等于更好。
惊讶?
不,这没什么奇怪的。尝试让MATLAB计算SQRT(2),精度为小数点后约500.000.000位。就这样
纳秒确实很重要。这里的数字越大,精度就是目标。
这不值得花时间和精力吗?当然,是的