簡體   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