········i = 0
········while i < k and n % p[i]!= 0:
············i = i + 1
········if i == k:
············p[k] = n
············k = k + 1
············result.append(n)
········n = n + 1
····return result
Эта реализация алгоритма поиска простых чисел содержит дополнительные ключевые слова. Следующий пример написан на чистом Python:
def primes(kmax):
""" Расчет простых чисел с помощью стандартного синтаксиса Python """
····p= range(1000)
····result = []
····if kmax > 1000:
········kmax = 1000
····k = 0
····n = 2
····while k < kmax:
········i = 0
········while i < k and n % p[i]!= 0:
············i = i + 1
········if i == k:
············p[k] = n
············k = k + 1
············result.append(n)
········n = n + 1
····return result
Обратите внимание: в версии Cython вы объявляете, что целые числа и массивы целых чисел будут скомпилированы в типы C, в то же время будет создан список Python:
Тип объявляется как целое число.
Переменные n, k и i объявляются как целые числа.
Мы заранее выделяем память для массива целых чисел p размером в 1000 элементов.
В чем же разница? В версии Cython вы можете увидеть объявление типов переменных и массива целых чисел, которые выглядят так же, как и в обычном С. Например, дополнительное объявление типа (целочисленного) в выражении cdef int n,k,i позволяет компилятору Cython генерировать более эффективный код С. Поскольку синтаксис несовместим со стандартным Python, он сохраняется в файлах с расширением *.pyx, а не с расширением *.py.
Каковы различия в скорости? Давайте проверим!
Модуль pyximport позволяет импортировать файлы с расширением *.pyx (например, primesCy.pyx) с помощью скомпилированной в Cython версии функции primes.
Команда pyximport.install() позволяет интерпретатору Python непосредственно запустить компилятор Cython для генерации кода C, который автоматически компилируется в библиотеку с расширением *.so. Далее Cython может легко и эффективно импортировать эту библиотеку в ваш код Python.
С помощью функции time.time() вы можете сравнить время выполнения этих двух вызовов, которые определяют 500 простых чисел. На стандартном ноутбуке (dual-core AMD E-450 1.6 GHz) мы получили следующие значения:
Cython time: 0.0054 seconds
Python time: 0.0566 seconds
А здесь результат работы встроенной машины ARM BeagleBone (http://beagleboard.org/Products/BeagleBone):
Cython time: 0.0196 seconds
Python time: 0.3302 seconds
Numba
Numba (http://numba.pydata.org/) — это компилятор для Python, поддерживающий NumPy (он является динамическим — just-in-time (JIT)). Компилирует аннотированный код Python (и NumPy) для LLVM (Low-Level Virtual Machine) (http://llvm.org/) с помощью особых декораторов. Вкратце, Numba использует LLVM для компилирования кода Python в машинный код, который может быть нативно выполнен во время работы программы.
Если вы используете Anaconda, установите Numba с помощью команды conda install numba. Если нет, установите его вручную. Вы должны заранее установить NumPy и LLVM (перед Numba).
Проверьте, какая версия LLVM вам нужна (на странице PyPI для llvmlite по адресу https://pypi.python.org/pypi/llvmlite), и загрузите ее для вашей ОС:
• сборки LLVM для Windows (http://llvm.org/builds/);
• сборки LLVM для Debian/Ubuntu (http://llvm.org/apt/);
• сборки LLVM для Fedora (https://apps.fedoraproject.org/packages/llvm);
• вы можете найти информацию о том, как устанавливать LLVM на основе исходного кода для других систем Unix, в разделе «Сборка компиляторов Clang + LLVM» (http://ftp.math.utah.edu/pub/llvm/);
• для OS X используйте команду brew install homebrew/versions/llvm37 (или выберите текущую версию).
Как только вы установите LLVM и NumPy, инсталлируйте Numba с помощью pip. Вам может понадобиться помочь установщику найти файл llvm-config, предоставив переменной среды LLVM_CONFIG соответствующий путь, например:
$ LLVM_CONFIG=/path/to/llvm-config-3.7 pip install numba
Чтобы использовать его в своем коде, декорируйте свои функции:
Без аргументов декоратор @jit выполняет ленивую компиляцию — сам решает, оптимизировать ли функцию и как это сделать.