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

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

В этой статье поговорим о том, как можно ускорить свой Python код при помощи библиотек, скомпилированных с помощью Nim.

Также узнаем, какие библиотеки на Python написаны с помощью Nim и даже напишем свой небольшой модуль.

Обложка статьи
Обложка статьи

Подготовка

Для того, чтобы начать - необходимо поставить Nim. Если он у вас уже есть - отлично, идем дальше.

Все действия ниже будут производиться с Nim 2.0.0 и с Python 3.10.9.

С помощью пакетного менеджера nimble ставим пакет nimpy, с помощью которого мы сможем разрабатывать Python библиотеки на Nim.

nimble install nimpy

Переходим к Python и возьмем какой-нибудь алгоритм для замера производительности, например фибоначчи. Создадим файл fib.py и напишем саму функцию.

def fib(n: int) -> int:
    if n == 0:
        return 0
    elif n < 3:
        return 1
    return fib(n - 1) + fib(n - 2)

Теперь вернемся к Nim и создадим файл nimfib.nim. Как это будет выглядеть здесь?

import nimpy  # импортируем библиотеку nimpy

# Объявляем функцию fib(n) 
func fib(n: int): int {.exportpy.} =
  if n == 0:
    return 0
  elif n < 3:
    return 1
  return fib(n - 1) + fib(n - 2)

Выглядит действительно схоже, не так ли? Попробуем скомпилировать в python библиотеку:

nim c -o:nimfib.pyd --tlsEmulation:off --passL:-static --threads:on --app:lib -d:danger --opt:speed nimfib

Эту команду можно вынести в отдельный файл.

Для Unix систем команда выше выглядит следующим образом:

nim c -o:nimfib.so --app:lib -d:danger --threads:on --opt:speed nimfib

При компиляции с помощью --threads:on Nim будет подставлять--tlsEmulation:on (только для Windows), что предотвращает правильную инициализацию среды выполнения Nim при вызове из внешнего потока (что всегда имеет место в случае модуля Python).

Теперь посмотрим, насколько быстро работают Nim и Python. Для этого ставим пакеты pytest и pytest-benchmark.

pip install pytest pytest-benchmark

Создадим файл main.py:

from timeit import default_timer
import pytest
import fib
import nimfib


@pytest.mark.benchmark(group="fibonacci", timer=default_timer)
def test_py_fib(benchmark):
    result = benchmark(fib.fib, 35)

@pytest.mark.benchmark(group="fibonacci", timer=default_timer)
def test_nim_fib(benchmark):
    result = benchmark(nimfib.fib, 35)

Теперь запустим это через pytest:

pytest main.py

А вот и результаты:

--------------------------------------------------------------------------------- benchmark 'fibonacci': 2 tests ---------------------------------------------------------------------------------
Name (time in ms)            Min                   Max                  Mean             StdDev                Median                IQR            Outliers     OPS            Rounds  Iterations
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_nim_fib             93.4353 (1.0)        117.2837 (1.0)        102.3561 (1.0)       7.9790 (1.0)         99.2676 (1.0)      11.3069 (1.0)           3;0  9.7698 (1.0)           9           1
test_py_fib           2,986.7212 (31.97)    3,013.6137 (25.70)    2,998.6946 (29.30)    11.7603 (1.47)     3,001.7616 (30.24)    20.1307 (1.78)          3;0  0.3335 (0.03)          5           1
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
====================================================================== 2 passed in 23.19s =======================================================================

Как вы можете видеть - Nim, скомпилированный в C быстрее Python в 30 раз.

Если мы скомпилируем Nim в C++ (заменив nim c на nim cpp), то получим уже следующие результаты:

--------------------------------------------------------------------------------- benchmark 'fibonacci': 2 tests ---------------------------------------------------------------------------------
Name (time in ms)            Min                   Max                  Mean            StdDev                Median               IQR            Outliers       OPS            Rounds  Iterations
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_nim_fib              9.4439 (1.0)         14.0821 (1.0)          9.7844 (1.0)      0.7489 (1.0)          9.5708 (1.0)      0.1119 (1.0)          7;15  102.2032 (1.0)         106           1
test_py_fib           3,003.1009 (317.99)   3,016.5476 (214.21)   3,009.6761 (307.60)   5.4503 (7.28)     3,010.4404 (314.55)   8.8961 (79.50)         2;0    0.3323 (0.00)          5           1
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
====================================================================== 2 passed in 23.19s ======================================================================= 

Разница в 300 раз, действительно впечатляет. Конечно, вы можете ускорить его еще больше, если хотите - у Nim достаточно параметров для компиляции.

Перейдем к более реальным примерам


Готовые библиотеки

Есть несколько реальных примеров использования nimpy для разработки Python библиотек:

  • faster-than-requests (исходный код) - тот же requests, но написан на Nim.

  • faster-than-csv (исходный код) - тот же csv, но на Nim.

  • nimporter (исходный код) - утилита, с помощью которой можно импортировать Nim файлы напрямую в Python. Компиляция происходит автоматически.

  • HappyX (исходный код) - веб-фреймворк, написанный на Nim и доступный как для Python, так и для NodeJS и JVM.

  • pyMeow (исходный код) - библиотека для написания читов с помощью Raylib, Python и Nim.


Кошки, собаки и Python классы

Давайте попробуем создать на стороне Nim объект Entity. Создадим файл entity.nim:

import nimpy
import strformat


type
  Entity* = ref object of PyNimObjectExperimental
    health: int
    maxHealth: int
    damage: int
    name: string


proc initEntity*(name: string, health: int, damage: int = 1): Entity {.exportpy: "create_entity".} =
  return Entity(
    name: name,
    health: health,
    maxHealth: health,
    damage: damage
  )


proc isAlive*(self: Entity): bool {.exportpy: "is_alive".} =
  return self.health > 0


proc hit*(self: Entity, other: Entity) {.exportpy.} =
  # Примитивная логика получения удара
  other.health -= self.damage
  if other.health <= 0:
    echo fmt"{other.name} погиб в бою от руки {self.name} 						
Источник: https://habr.com/ru/articles/779370/


Интересные статьи

Интересные статьи

Геоаналитика и пространственный анализ — это мощные инструменты, которые позволяют бизнесам принимать более обоснованные решения на основе пространственных данных и информации о местоположении. Ге...
В этом руководстве я покажу, как протестировать использование внешнего API с помощью Python моков.Интеграция со сторонними приложениями — отличный способ расширить функциональность любого продукта. Од...
Данная статья описывает баг и его решения в контексте ReactJS + Server-Side Rendering, но это также актуально для всех фреймворков большой тройки так и для чистого JS.При разработке сайта мы столкнули...
Большая часть информации в мире хранится в виде таблиц, которые можно найти в Интернете или в базах данных и документах. В таблицах может находиться всё что угодно, от технических характеристик потреб...
Всем привет. Решил несколько дополнить статью C/C++ из Python. Передача стандартных типов, таких как int, bool, float и так далее довольно проста, но мало необходима. С такими данными быстро сп...