Рубрики
Без рубрики

Numba: Сделайте свой код python в 100 раз быстрее

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

Автор оригинала: Pankaj Kumar.

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

Что делает python медленным?

Python использовался для научных вычислений в течение длительного периода времени. Хотя Python-отличный язык для прототипирования, python barebone не имеет передовых технологий для выполнения таких огромных вычислений. Что делает python по своей сути медленным, так это, по иронии судьбы, функции, которые делают Python таким популярным как язык. Давайте рассмотрим их один за другим:

  • Динамически типизированный : Python-это динамически типизированный язык, т. е. пользователям не нужно указывать тип данных, связанный с переменной. Хотя это значительно упрощает работу на верхней поверхности, внутренние механизмы усложняются многими складками, поскольку интерпретатору необходимо проверять тип данных и связанное с ними преобразование каждый раз, когда выполняется операция. Эти увеличенные и сложные инструкции в основном отвечают за скорость python.
  • Накладные расходы на память : Из-за гибкой природы Python для каждого небольшого объекта, такого как int в списке, необходимо выделять отдельную память (в отличие от C, который занимает непрерывный кусок памяти для массива). Это означает, что объекты в списке не помещаются рядом друг с другом в памяти, что влияет на затраты времени для каждой операции выборки.
Массив Против Списка Numba
  • Некомпилированные : Компиляторы, такие как LLVM, GCC могут заглянуть в программу и выполнить некоторые высокоуровневые оптимизации, что экономит как память, так и скорость. Интерпретатор Python, с другой стороны, не знает о следующей строке выполнения, поэтому он не применяет никаких оптимизаций, экономящих время.
  • GILLock : Глобальная блокировка интерпретатора(GIL) не позволяет многопоточность . Это гарантирует, что только один поток выполняет байтовый код Python. Это упрощает реализацию CPython, делая объектную модель неявно безопасной от параллельного доступа.

В этой статье мы увидим, как numba преодолевает эти трудности и как ее можно использовать для ускорения нашего кода до уровня C/C++ и FORTRAN.

Скриншот С 2021 Года 03 17 18 31 46

Что такое Numba?

Согласно официальной документации, “Numba-это компилятор точно в срок для Python, который лучше всего работает с кодом, использующим массивы NumPy, функции и циклы” . JIT-компилятор является одним из проверенных методов повышения производительности интерпретируемых языков. Во время выполнения программы компилятор LLVM компилирует код в машинный код, который обычно намного быстрее, чем интерпретируемая версия кода. Как обсуждалось ранее, компилятор может добавить некоторые высокоуровневые оптимизации, которые могут принести пользу пользователю как с точки зрения памяти, так и скорости.

Numba поставляется с дистрибутивом Anaconda, а также на колесах, поэтому его можно установить с помощью

conda install numba

или,

pip install numba

Примечание: Пользователям Linux может потребоваться использовать pip3 вместо pip .

Использование Numba в Python

Numba использует декораторы функций для увеличения скорости работы функций. Важно, чтобы пользователь заключил вычисления внутри функции. Наиболее широко используемым декоратором, используемым в numba, является декоратор @jit. Используя этот декоратор, вы можете пометить функцию для оптимизации JIT-компилятором Numba. Давайте рассмотрим пример использования тривиальной функции.

from numba import jit
import numpy as np

@jit            # Placing the @jit marks the function for jit compilation
def sum(a, b):
    return a + b

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

Пользователь может испытать некоторую задержку при выполнении функции в первый раз. Этот очевидный временной разрыв обусловлен компиляцией функции. После компиляции пользователь может ожидать нормальной скорости скомпилированных функций numba. Один из распространенных трюков заключается в использовании небольшой фиктивной переменной для выполнения кода в первый раз.

Примечание : Не изменяйте тип данных переменной внутри функции. Изменение типа данных означает, что numba больше не может определить тип данных и правильно оптимизировать функцию.

1. Нетерпеливый режим

Одним из недостатков этого подхода, описанного выше, является то, что мы должны дождаться первого выполнения компиляции. Мы можем преодолеть это с помощью нетерпеливого режима. В нетерпеливом режиме мы указываем тип входных данных , поэтому компилятору не нужно делать вывод из входных данных и компилировать функцию на ходу. Это называется нетерпеливым исполнением, и вот как мы можем это сделать,

@jit(int32(int32, int32))
def sum(a, b):
    return a + b

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

2. Отсутствие режима GIL

Компиляция кода освобождает нас от блокировки глобального интерпретатора python. Мы можем указать не использовать GIL, используя nogil=True

@jit(nogil=True)
def sum(a, b):
    return a + b

3. Режим без python

Существует два режима выполнения- python и object mode. В режиме nopython компилятор выполняет код без участия интерпретатора. Это лучший способ компиляции с помощью numba.jit().

@jit(nopython=True)
def sum(a, b):
    return a + b

Numba лучше всего работает с массивами и функциями numpy. Вот пример из официального документа, использующего функцию numpy.

from numba import jit
import numpy as np

x = np.arange(100).reshape(10, 10)

@jit(nopython=True)
def go_fast(a): # Function is compiled to machine code when called the first time
    trace = 0.0
    for i in range(a.shape[0]):   # Numba likes loops
        trace += np.tanh(a[i, i]) # Numba likes NumPy functions
    return a + trace              # Numba likes NumPy broadcasting

print(go_fast(x))

Вывод

Numba предлагает скорость по сравнению с подобными C/C++, FORTRAN, Java и т. Д. не затрагивая ни одного синтаксического сахара python. Одним из недостатков numba является то, что он делает код python менее гибким, но позволяет точно контролировать переменные. Numba может облегчить вашу жизнь, если вы выполняете тяжелое научное моделирование (которое требует быстрой обработки и возможностей распараллеливания) с использованием python.

Рекомендации