Осмысление больших данных

Заставить Python работать так же быстро, как C

Более быстрый код Python с Numba

Проблема скорости

Хотя общепризнано, что Python, в основном из-за своего скудного синтаксиса, может выступать в качестве отличного языка прототипирования, у него есть недостаток, который обычно упоминается в дебатах о стиле «войны языков программирования»: скорость. По сравнению с другими языками программирования, Python выполняет стандартные алгоритмы тестирования намного медленнее.

Принимая во внимание самое быстрое время выполнения для нескольких популярных языков программирования из теста бинарного дерева в The Computer Language Benchmarks Game, 48,03 секунды Python не имеют никаких шансов против 0,94 секунды в C ++ или 1,54 секунды в C. типизированный язык, Python обеспечивает чрезвычайно высокую скорость прототипирования, но не может конкурировать со временем выполнения C ++, C, Fortran, а также нескольких других компилируемых языков.

Быстрое прототипирование + быстрое время выполнения = Numba

Numba сочетает в себе лучшее из миров быстрого прототипирования и быстрого выполнения с помощью JIT-компилятора для Python. Все это на самом деле означает, что ваш код будет компилироваться только во время выполнения, а не раньше. При этом Numba позволяет повысить скорость вашего кода Python на «один-два порядка». [2] Однако фактический прирост скорости от использования Numba во многом зависит от каждого конкретного варианта использования, поскольку проект ориентирован на научные вычисления. Приложения.

Установка Numba

Одно из больших преимуществ Numba - простота использования. В отличие от более или менее сложных процедур установки, необходимых для альтернативных способов ускорения Python, Numba может быть полностью установлена ​​с использованием pip или conda.

Оба способа чрезвычайно просты и должны сразу работать с большинством сред обработки данных. Используя Anaconda, conda install numba установит все, что требуется. То же самое и с pip install numba.

Когда использовать Numba

После установки Numba может помочь сделать код Python намного быстрее. Однако есть три основных критерия, которые служат руководством для определения того, насколько подходит Numba для конкретной задачи и, следовательно, ее потенциал для ускорения Python.

  1. Как упоминалось выше, Numba фокусируется на ускорении научных приложений. Таким образом, чем больше код состоит из математических операций, тем больше Numba сможет помочь.
  2. Что касается первого критерия, Numba особенно хорошо работает с NumPy. Скорее всего, код Python, ориентированный на математические операции, будет содержать много NumPy. Однако важно отметить, что Numba не поддерживает все функции NumPy, и некоторые из них, возможно, придется реализовать на необработанном Python и поддерживаемых функциях NumPy, чтобы их можно было использовать.
  3. Чем больше петель, тем лучше. Как правило, Numba позволяет значительно сэкономить время, когда код содержит несколько очень длинных циклов.

Включение Турбо

Еще одна причина использования Numba - способ ее интеграции с другим кодом Python. Единственное требование для использования Numba - это добавление декоратора к функции, которую нужно ускорить.

В приведенном выше примере декоратор @jit(nopython=True) сигнализирует Numba о необходимости работать в режиме nopython в отличие от альтернативного объектного режима Numba. По умолчанию для аргумента nopython установлено значение false, хотя он создает гораздо более быстрый код из-за связанных с этим ограничений на количество, например, поддерживаемых функций NumPy. Вместо @jit(nopython=True) можно также использовать сокращение @njit.

Поскольку код функции monte_carlo_pi соответствует как минимум двум из трех требований, которые делают Numba многообещающим вариантом использования из-за цикла for и сосредоточения внимания на математических вычислениях, добавление декоратора @njit должно обеспечить приличный прирост производительности.

В то время как чисто питоническая версия функции начинает резко замедляться при передаче ей примерно 100 миллионов выборок, эквивалентная версия Numba сохраняет гораздо более высокий уровень производительности, при этом относительный разрыв между обоими вариантами только увеличивается с увеличением вычислительной нагрузки.

Больше украшения

Ленивая компиляция позволяет Numba решать, как оптимизировать код. Как правило, этот вариант реализуется быстро и сводит к минимуму количество потенциально возможных ошибок. Декоратор @jit сообщает Numba о ленивой компиляции.

Кроме того, ленивая компиляция также позволит вам сохранить более высокую степень гибкости. По сути, он может дать функциям Python приличный прирост скорости, в то же время обеспечивая высокую скорость прототипирования.

Активная компиляция позволяет лучше контролировать сигнатуру функции, что может улучшить читаемость кода (и, возможно, производительность). В то же время указание подписи также снижает гибкость кода и может привести к ошибкам, которые легко не заметить. Подписи добавляются к декораторам над оптимизируемой функцией. Например, @jit(int64(int64)) описывает функцию, которая принимает на вход целое число и возвращает целое число. Numba также позволяет указывать массивы в подписях с помощью следующего синтаксиса: @jit(int64(int64[:])). Ранее упомянутая подпись будет определять массив целых чисел в качестве входных данных и целых чисел в качестве выходных данных функции.

Как указывалось во введении к активной компиляции, быстрое прототипирование может привести к необнаруженным ошибкам. Сигнатура функции f() ожидает массив целых чисел и вернет целое число. При передаче массива [1,2,3,4] правильным результатом будет 10 + 2.5 = 12.5. Однако из-за сигнатуры функции приведенный выше вызов функции вернет 12 без создания исключения. Подпись, дающая ожидаемый результат, была бы, например, @jit(float64(int64[:]). Следовательно, крайне важно правильно сформулировать сигнатуру каждой функции при использовании активной компиляции с Numba.

Однако самый мощный вариант jit-декоратора Numba - это @jit(nopython=True) или эквивалентный @njit. Если активировать режим nopython, рассматриваемая функция не будет использовать Python C API и будет создавать гораздо более быстрый код. В отличие от @jit, принуждение Numba к использованию режима nopython предотвратит откат к более медленному объектному режиму, но также потребует гораздо больше времени на разработку при подготовке, а также будет менее снисходительным. Запуск в объектном режиме допускает использование других стандартных пакетов анализа данных, таких как Pandas, тогда как режим nopython - нет.

Резюме

Хотя возможности Numba намного шире, чем методы, описанные в этой статье, хорошее владение и понимание того, как работать с @jit декоратором, - это большой шаг от кажущегося бесконечным циклов for и к более эффективному научному коду.

Когда дело доходит до быстрого прототипирования и экспериментов, Numba отлично интегрируется с Python благодаря быстрому процессу установки и простоте использования. Вместо того, чтобы устанавливать совершенно новый компилятор или смешивать код Python с другим языком, использование Numba позволяет программистам Python взяться за дело и сосредоточиться на своем коде так, как они это делали бы без Numba.

Тем не менее, Numba - это не универсальный подход. Каждый потенциальный вариант использования следует рассматривать отдельно, поскольку большая экономия времени за счет использования режима nopython достигается за счет невозможности использовать стандартные пакеты анализа данных, такие как Pandas. Поэтому, как правило, большинство приложений, вероятно, получат достаточную выгоду от того, чтобы позволить Numba выполнять всю работу по оптимизации через декоратор @jit. С другой стороны, расширенные варианты использования, требующие минимально возможного времени выполнения, требуют дополнительных затрат времени на обеспечение их совместимости с Numba из-за богатой экосистемы и обширной функциональности, с которыми поставляется проект.

Источники:

[1] Бинарные деревья. Игра "Тесты компьютерного языка". По состоянию на 2 августа 2021 г. https://benchmarksgame-team.pages.debian.net/benchmarksgame/performance/binarytrees.html.

[2] Нумба. Документация Numba - документация Numba 0.53.1-py3.7-linux-x86_64.egg. По состоянию на 2 августа 2021 г. https://numba.readthedocs.io/en/stable/index.html.