繁体   English   中英

MATLAB比Python更快(简单的小实验)

[英]Is MATLAB faster than Python (little simple experiment)

我读过这个( MATLAB比Python快吗? ),我发现它有很多ifs。

我在仍在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
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一样快?


UPDATE

我在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

结果

8.218999862670898
0.00016435734428313955

我会在一段时间内尝试NumPy

首先,使用time不是测试这样的代码的好方法。 但是,让我们忽略它。


当你的代码执行大量循环并且每次循环都重复非常相似的工作时, PyPy的JIT会做得很好。 当代码每次执行完全相同的操作时,对于可以从循环中提取的常量值,它会做得更好。 另一方面,CPython必须为每个循环迭代执行多个字节码,因此速度很慢。 通过对我的机器的快速测试,CPython 3.4.1需要24.2秒,但PyPy 2.4.0 / 3.2.5需要0.0059秒。

IronPython和Jython也是JIT编译的(虽然使用更通用的JVM和.NET JIT),因此它们也比CPython更快地进行这种工作。


您通常也可以通过使用NumPy数组和向量操作而不是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))

其他选项包括在Cython中编写部分代码(编译为Python的C扩展),并使用Numba ,JIT编译CPython中的代码。 对于这样的玩具程序,两者都不合适 - 如果您只是尝试优化一次性24秒进程,那么自动生成和编译C代码所花费的时间可能会浪费运行C代码而不是Python代码所节省的时间。 但在现实生活中的数值编程中,两者都非常有用。 (两者都与NumPy很好地配合。)

并且总会有新项目出现。

一个(有点受过教育的)猜测是,在MATLAB执行时,python不会对代码执行循环展开 这意味着MATLAB代码执行一个大型计算而不是许多(!)较小的计算。 这是使用PyPy而不是CPython的主要原因,因为PyPy 会循环展开

如果你正在使用python 2.X,你应该用range替换xrange ,因为range (在python 2.X中)会创建一个迭代的列表。

问:如何更改py脚本以使其运行速度与MATLAB一样快?

因为abarnet已经给了你很多知识渊博的方向,让我加上我的两分钱(以及一些定量结果)。

(同样地,我希望你能原谅跳过for:并承担更复杂的计算任务)

  • 检查代码是否有任何可能的算法改进,值重用和注册/缓存友好的安排( numpy.asfortranarray()等)

  • 尽可能在numpy使用矢量化代码执行/循环展开

  • 使用类似LLVM编译器的numba来获得代码的稳定部分

  • 仅在代码的最终等级上使用附加(JIT) - 编译器技巧(nogil = True,nopython = True)以避免常见的过早优化错误

可能的成就确实很大:

纳秒很重要的地方

一个初始代码样本来自FX竞技场(毫秒,微秒和(浪费)纳秒确实很重要 - 检查50%的市场事件你有远远少于900毫秒的行为(端到端双向交易) ,而不是谈论HFT ...)处理EMA(200,CLOSE) - 在大约5200多行的数组中,最后200英镑美元蜡烛/柱上的非平凡指数移动平均线:

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

从大约11499 [us](是的,从大约11500微秒到大约541 [我们])

#       classical numpy
# aClk.start();X[:,7] = EMA_fromPrice( 200, price_H4_CLOSE );aClk.stop()
# 11499L

但是,如果你对算法更加谨慎,并重新设计它以便更智能,更有效地工作, 结果更加富有成果

@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核心处理


46倍加速到大约四分之一毫秒

# ___________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位的精度。 它去了。

纳秒很重要。 在这里,精度是目标。


这不值得时间和努力吗? 当然是啦。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM