Является ли MATLAB быстрее, чем Python (небольшой простой эксперимент)

Я прочитал это ( Является ли MATLAB быстрее, чем Python? ), И я нахожу, что у него много.

Я пробовал этот небольшой эксперимент на старом компьютере, который все еще работает в 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?


ОБНОВИТЬ

Я попробовал тот же эксперимент в 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 через некоторое время.

3 Solutions collect form web for “Является ли MATLAB быстрее, чем Python (небольшой простой эксперимент)”

Во-первых, использование time не является хорошим способом протестировать такой код. Но давайте проигнорируем это.


Когда у вас есть код, который выполняет много циклов и повторяет очень схожую работу каждый раз через цикл, JIT PyPy сделает отличную работу. Когда этот код делает то же самое каждый раз, до постоянных значений, которые могут быть сняты из цикла, это будет еще лучше. CPython, с другой стороны, должен выполнить несколько байткодов для каждой итерации цикла, поэтому он будет медленным. Из быстрого теста на моей машине CPython 3.4.1 занимает 24,2 секунды, но PyPy 2.4.0 / 3.2.5 занимает 0.0059 секунды.

IronPython и Jython также скомпилированы JIT (хотя используют более общие JVM и .NET JIT), поэтому они, как правило, быстрее, чем CPython для такой работы.


Вы также можете ускорить работу, как это происходит в самом CPython, используя массивы NumPy и векторные операции вместо списков и циклов Python. Например, следующий код занимает 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 (которая компилируется в расширение C для Python) и использование Numba , который JIT-компилирует код внутри CPython. Для таких игрушечных программ ни один из них не может быть подходящим – время, затрачиваемое на автоматическое генерирование и компиляцию кода C, может затушить время, сохраненное при запуске кода C вместо кода Python, если вы только пытаетесь оптимизировать одноразовый 24-секундный процесс , Но в реальном численном программировании оба они очень полезны. (И оба прекрасно играют с NumPy.)

И на горизонте всегда есть новые проекты.

A (несколько образованная) догадка заключается в том, что python не выполняет цикл, развернутый на вашем коде, в то время как MATLAB делает . Это означает, что код MATLAB выполняет одно большое вычисление, а не множество (!) Меньших. Это основная причина для перехода с PyPy, а не с CPython, так как PyPy делает разворот цикла .

Если вы используете python 2.X, вы должны заменить range для xrange , так как range (в python 2.X) создает список для итерации.

В: Как мне изменить скрипт py чтобы он работал так же быстро, как MATLAB?

поскольку abarnet уже дал вам много знающих направлений, позвольте мне добавить мои два цента (и некоторые количественные результаты).

(аналогично, я надеюсь, вы прощаете, чтобы пропустить for: и принять более сложную вычислительную задачу)

  • просмотрите код для любых возможных алгоритмических улучшений, повторного использования ценности и numpy.asfortranarray() с регистром / кэшем ( numpy.asfortranarray() et al)

  • использование векторизованного кода-выполнения / циклического разворачивания в numpy , где это возможно

  • используйте LLVM-компилятор как numba для стабильных частей вашего кода

  • использовать дополнительные (JIT) -компиляторы трюки (nogil = True, nopython = True) только для окончательной оценки кода, чтобы избежать общей ошибки преждевременной оптимизации

Достижения, которые возможны, действительно огромны:

Где наносекунды

Образец исходного кода берется с FX арены (где миллисекунды, микросекунды и (впустую) наносекунды действительно имеют значение – проверьте, что для 50% рыночных событий у вас гораздо меньше 900 миллисекунд, чтобы действовать (сквозная двунаправленная транзакция) , не говоря уже о HFT …) для обработки EMA(200,CLOSE) – нетривиальная экспоненциальная скользящая средняя за последние 200 GBPUSD свечей / баров в массиве из примерно 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 компиляции numba сделал улучшение по сравнению с обычным выполнением кода python / numpy

21x до примерно половины миллисекунды

 # 541L 

от примерно 11499 [нас] (да, примерно от 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 

И окончательная обработка полировки для обработки с несколькими процессорами


46x ускорилось примерно до четверти миллисекунды

 # ___________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 мест за десятичной точкой. Там идет.

Наносекунды имеют значение. Чем больше здесь, где точность является целью.


Разве это не стоит времени и усилий? Конечно да.

Python - лучший язык программирования в мире.