DEV Community

Cover image for Ускоряем Elixir: интеграция с нативным кодом (NIF, Ports и др.)
Artyom Molchanov
Artyom Molchanov

Posted on

Ускоряем Elixir: интеграция с нативным кодом (NIF, Ports и др.)

⚠️ Важно: Перед внедрением новых языков в проект сначала убедитесь, что код на Elixir был максимально оптимизирован. В большинстве случаев грамотная оптимизация текущего кода значительно улучшает производительность приложения и иногда даёт лучшие результаты, нежели добавление другого языка программирования.


Elixir и Erlang — отличные языки для разработки масштабируемых и отказоустойчивых систем. Но иногда нужно выжать максимум производительности или использовать библиотеку, доступную лишь на другом языке. Если вы попали именно в такую ситуацию или просто хотите узнать, как совместить два ваших любимых языка программирования, эта статья для вас!


🔍 Когда нужна интеграция с нативным кодом

Прежде чем углубляться в технические детали, важно понять, когда стоит рассматривать интеграцию с нативным кодом:

1. Вычислительно-интенсивные задачи

BEAM создан для конкурентности, а не для вычислений. Если ваше узкое место — CPU-bound операции:

  • 🧮 Математические вычисления — Линейная алгебра или операции с матрицами
  • 🔐 Криптография — Шифрование/Дешифрование больших объёмов данных
  • 🎨 Обработка медиа — Изображения, видео, аудио
  • 🧠 Машинное обучение - инференс моделей, векторные операции

2. Аппаратное взаимодействие

Когда требуется низкоуровневый доступ к оборудованию:

  • 📟 Embedded-системы — Raspberry Pi, микроконтроллеры (Для этого есть Nerves в Elixir, но его иногда может не хватить)
  • 🎮 Специфические драйверы — нестандартные устройства
  • 📊 GPU-вычисления — CUDA, OpenCL

3. Переиспользование существующего кода

  • 🏛️ Проверенные временем библиотеки на C/C++
  • 📚 Экосистемные преимущества других языков (например, Python для ML)
  • 🔧 Избегание "изобретения велосипеда"

4. Профилирование и узкие места

Типичные признаки, что пора задуматься о нативном коде:

# До оптимизации - 1000мс defmodule SlowModule do def process_data(data) do # Потенциальное узкое место для нативной оптимизации Enum.reduce(data, 0, fn x, acc -> complex_calculation(x) + acc end) end defp complex_calculation(x) do # Представьте CPU-интенсивные вычисления # которые плохо масштабируются в BEAM end end # Вы исчерпали возможности оптимизации на Elixir и всё ещё медленно?  # Возможно, пора подключать нативный код! 
Enter fullscreen mode Exit fullscreen mode

Нативные расширения превращают Elixir в универсальный инструмент, где BEAM решает всё, кроме критических вычислений. Это открывает двери к ML, hardware, видеообработке и всему, где важна скорость.


⚖️ Сравнение методов интеграции

Выбор правильного метода интеграции критически важен для успеха проекта. Вот сравнительная таблица методов интеграции с их плюсами и минусами:

Метод Скорость Безопасность BEAM Сложность реализации Поддержка языков Коммуникационные затраты Асинхронность Идеальные сценарии использования
NIF ⚡⚡⚡⚡⚡ ❌ Опасно 🔧🔧🔧 Средняя C, C++ Нет (прямой вызов) ❌ Блокирует планировщик Микросервисы, долгие CPU-bound задачи
Dirty NIF ⚡⚡⚡⚡ ⚠️ Условно безопасно 🔧🔧🔧 Средняя C, C++ Нет (прямой вызов) ✅ Не блокирует основной планировщик Долгие вычисления (>1ms)
Port ⚡⚡ ✅✅ Полностью безопасно 🔧 Простая Любой Высокие (IPC) ✅ Процессная изоляция Python, Go, Bash-скрипты
Port Driver ⚡⚡⚡⚡ ✅ Безопасно 🔧🔧🔧🔧 Сложная C, C++ Низкие ✅ Выделенный поток Обработка видео/аудио
gRPC ⚡⚡ ✅✅ Полностью безопасно 🔧🔧 Средняя Любой с поддержкой gRPC Средние (сеть) ✅ Отдельный сервис Микросервисная архитектура
Rustler ⚡⚡⚡⚡ ✅ Безопасно 🔧🔧 Средняя Rust Нет (прямой вызов) ✅ Поддержка асинхронного API Альтернатива C NIF
Zigler ⚡⚡⚡⚡⚡ ✅ Безопасно 🔧🔧 Средняя Zig Нет (прямой вызов) ✅ Безопаснее стандартных NIF Альтернатива C в NIF

Визуальное сравнение по ключевым метрикам

Скорость: Безопасность: Простота: NIF █████ Port █████ Port █████ Dirty NIF ████ Dirty NIF ███ gRPC ████ Rustler ████ Rustler ████ Rustler ████ Zigler █████ Zigler ████ Zigler ████ Port Driver ████ Port Driver ████ NIF ███ Port ██ gRPC █████ Port Driver █ gRPC ██ NIF █ Dirty NIF ███ 
Enter fullscreen mode Exit fullscreen mode

🛠️ Немного о механизмах интеграции


🧠 NIFs — максимальная производительность

Native Implemented Functions (NIFs) — самый быстрый способ интеграции, но и самый опасный. Они выполняются напрямую в потоке планировщика BEAM, обеспечивая молниеносную скорость за счет отсутствия накладных расходов.

Как работают NIF?

  1. Компиляция: Нативный код (C/Rust/Zig) компилируется в динамическую библиотеку (.so, .dll)
  2. Загрузка: BEAM загружает библиотеку при старте модуля через :erlang.load_nif/2
  3. Прямое выполнение: Функции выполняются в том же потоке, что и вызывающий Elixir-код

✅ Преимущества

  • Молниеносная скорость: Вызов занимает ~0.1-1 μs (в 100-1000 раз быстрее Ports)
  • Доступ к BEAM API: Прямая работа с термами Erlang
  • Отсутствие сериализации: Нет накладных расходов на кодирование/декодирование данных
  • Распространение: Библиотека идёт вместе с OTP-приложением

❌ Недостатки

  • Риск падения всей ВМ: Ошибка в NIF убьёт весь BEAM
  • Блокировка планировщика: Долгие NIF замораживают многопоточность
  • Сложность отладки: Трудно обнаружить утечки памяти
  • Платформозависимость: Требуется компиляция под каждую архитектуру

Dirty NIFs — безопасная альтернатива

С Erlang/OTP 20+ появились Dirty NIFs — специальный вид NIF, который исполняется в выделенном пуле потоков, что позволяет выполнять долгие вычисления без блокировки планировщика BEAM.

// Определение Dirty NIF static ErlNifFunc nif_funcs[] = { {"long_computation", 1, long_computation_nif, ERL_NIF_DIRTY_CPU} }; 
Enter fullscreen mode Exit fullscreen mode

💡 Совет: Используйте ERL_NIF_DIRTY_CPU для CPU-bound операций и ERL_NIF_DIRTY_IO для операций ввода/вывода

🔌 Ports — полная изоляция

Ports — способ для взаимодействия с внешними программами через стандартные потоки ввода-вывода (stdin/stdout). Это самый безопасный способ интеграции, так как внешняя программа запускается в отдельном процессе ОС.

Как работают Ports?

  1. Запуск: Elixir запускает внешнюю программу как отдельный OS-процесс
  2. Обмен данными: Коммуникация через стандартные потоки (stdin/stdout)
  3. Изоляция: Падение внешней программы не влияет на BEAM

✅ Преимущества

  • Полная безопасность: Изоляция гарантирует стабильность BEAM
  • Языковая агностичность: Работает с любым языком программирования
  • Простота отладки: Внешнюю программу можно тестировать отдельно
  • Отсутствие зависимостей: Не требует специфичных для BEAM библиотек

❌ Недостатки

  • Высокие накладные расходы: ~100-500 μs на вызов
  • Сериализация: Требуется преобразование данных (обычно в JSON)
  • Блокирующие вызовы: По умолчанию блокирует вызывающий процесс

🚗 Port Drivers — золотая середина

Port Drivers — производительная альтернатива Ports, но более сложная. Это драйверы на языке C, встроенные непосредственно в адресное пространство BEAM и работающие в отдельных потоках.

Как работают Port Drivers?

  1. Загрузка: BEAM загружает C-библиотеку в свое адресное пространство
  2. Выделение потока: Драйвер работает в отдельном потоке
  3. Асинхронность: Обмен данными через очередь сообщений

✅ Преимущества

  • Скорость: Значительно быстрее обычных портов
  • Безопасность: Меньший риск чем у NIF
  • Асинхронность: Поддержка неблокирующих операций
  • Удобство: Не требует запуска отдельного процесса

❌ Недостатки

  • Сложность: Требует знания C API Erlang
  • Ограниченность: Работает только с C/C++
  • Меньшая документация: Не так много примеров и руководств

🐊 Zigler - Обёртка над NIFs для Zig

Zigler — Библиотека, позволяющая писать нативные расширения на языке Zig. Встраивает компилятор Zig прямо в цикл компиляции Elixir и позволяет напрямую писать код на Zig в модулях Elixir

✅ Преимущества

  • Минимальные накладные расходы на вызов нативного кода
  • Безопасность памяти без сборщика мусора
  • Прямой доступ к низкоуровневым операциям
  • Более простая компиляция в сравнении с другими нативными расширениями
  • Поддержка горячей перезагрузки кода

❌ Недостатки

  • Zig — относительно молодой язык с меньшим сообществом
  • Более высокий порог входа для разработчиков Elixir
  • Ограниченная экосистема библиотек в сравнении с Rust

Rustler - Обёртка над NIFs для Rust

Rustler — это библиотека для создания нативных расширений Erlang/Elixir на языке Rust. Обеспечивает безопасный биндинг между Rust и Erlang/Elixir, позволяя писать NIFs на Rust.

✅ Преимущества

  • Безопасность памяти на уровне компиляции
  • Высокая производительность для вычислительно сложных задач
  • Богатая экосистема пакетов Rust (crates)
  • Защита от сбоев в нативном коде (защита BEAM от падения)
  • Параллельное выполнение без блокировки планировщика BEAM

❌ Недостатки

  • Усложненный процесс сборки и зависимостей
  • Требует знания двух различных парадигм программирования
  • Возможные проблемы с совместимостью версий
  • Потенциальные узкие места на границе сред выполнения

🌐 gRPC и другие протоколы

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

✅ Преимущества gRPC для Elixir

  • Схема контрактов: Строгие типы через Protocol Buffers
  • Двунаправленный стриминг: Поддержка потоковой передачи в обе стороны
  • Кросс-платформенность: Поддержка множества языков
  • Производительность: Более эффективен чем REST/JSON

❗️Пример с gRPC был слишком объёмен, чтобы рассмотреть его в рамках этой статьи, из-за чего он не был включён в неё. Подробнее о gRPC на Elixir можно почитать вот тут - elixir-grpc


🧪 Практические примеры интеграции

📚 Цель статьи — дать обзор доступных способов интеграции с нативным кодом. Глубокие реализации и edge-кейсы здесь опущены, чтобы сохранить баланс между теорией и применением.

🔍 Критерии выбора метода интеграции

Прежде чем перейти к примерам, определим ключевые факторы выбора:

  1. Производительность: Насколько быстро работает вызов
  2. Безопасность: Риск для стабильности BEAM
  3. Сложность реализации: Легко ли внедрить решение
  4. Поддержка языка: Насколько хорошо язык работает с BEAM

1. ⚙️ C — максимальная производительность с NIF и Port Drivers

Оптимальные методы:

  • NIF — для мгновенных операций (<1ms)
  • Port Drivers — для долгих или асинхронных задач

Почему именно так?

C имеет прямую совместимость с BEAM, что делает его идеальным для:

  • Критически важных по производительности задач
  • Низкоуровневых операций (работа с железом, GPU)
  • Интеграции с существующими C-библиотеками

Пример 1: Быстрый NIF для хеширования (оптимально для C)

// hash_nif.c #include <erl_nif.h> #include <openssl/sha.h>  static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary input; if (!enif_inspect_binary(env, argv[0], &input)) { return enif_make_badarg(env); } unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256(input.data, input.size, hash); ErlNifBinary output; enif_alloc_binary(SHA256_DIGEST_LENGTH, &output); memcpy(output.data, hash, SHA256_DIGEST_LENGTH); return enif_make_binary(env, &output); } static ErlNifFunc nif_funcs[] = { {"sha256", 1, sha256_nif} }; ERL_NIF_INIT(Elixir.CryptoNif, nif_funcs, NULL, NULL, NULL, NULL) 
Enter fullscreen mode Exit fullscreen mode

Elixir часть:

defmodule CryptoNif do @on_load :load_nif def load_nif do :erlang.load_nif(Path.expand("./hash_nif"), 0) end def sha256(_data), do: raise "NIF not loaded!" end 
Enter fullscreen mode Exit fullscreen mode

Компиляция C-исходника:

Для запуска данного примера вам нужна openssl библиотека

# Для Ubuntu/Debian sudo apt-get install libssl-dev 
Enter fullscreen mode Exit fullscreen mode
# Для CentOS/RHEL sudo yum install openssl-devel 
Enter fullscreen mode Exit fullscreen mode
# Для macOS (если используете Homebrew) brew install openssl 
Enter fullscreen mode Exit fullscreen mode
gcc -shared -fPIC -o hash_nif.so hash_nif.c \ -I /usr/lib/erlang/erts-15.2.7/include \ # Путь до Erlang зависит от вашей системы -I /usr/include/openssl \ -L /usr/lib/openssl \ -lssl -lcrypto 
Enter fullscreen mode Exit fullscreen mode

Результат:

iex(1)> CryptoNif.sha256("test") <<159, 134, 208, 129, 136, 76, 125, 101, 154, 47, 234, 160, 197, 90, 208, 21, 163, 191, 79, 27, 43, 11, 130, 44, 209, 93, 108, 21, 176, 240, 10, 8>> 
Enter fullscreen mode Exit fullscreen mode

Пример 2: Port Driver для реверса строки

// reverse_driver.c #include "erl_driver.h" #include <string.h>  typedef struct { ErlDrvPort port; } DriverData; static void reverse_and_send(ErlDrvData drv_data, char* buf, ErlDrvSizeT len) { DriverData* d = (DriverData*)drv_data; for (ErlDrvSizeT i = 0; i < len / 2; i++) { char temp = buf[i]; buf[i] = buf[len - 1 - i]; buf[len - 1 - i] = temp; } driver_output(d->port, buf, len); } static ErlDrvData driver_start(ErlDrvPort port, char* command) { DriverData* d = (DriverData*)driver_alloc(sizeof(DriverData)); d->port = port; return (ErlDrvData)d; } static void driver_stop(ErlDrvData drv_data) { DriverData* d = (DriverData*)drv_data; driver_free(d); } static ErlDrvEntry driver_entry = { .init = NULL, .start = driver_start, .stop = driver_stop, .output = reverse_and_send, .ready_input = NULL, .ready_output = NULL, .driver_name = "reverse_driver", .finish = NULL, .handle = NULL, .control = NULL, .timeout = NULL, .outputv = NULL, .ready_async = NULL, .flush = NULL, .call = NULL, .extended_marker = ERL_DRV_EXTENDED_MARKER, .major_version = ERL_DRV_EXTENDED_MAJOR_VERSION, .minor_version = ERL_DRV_EXTENDED_MINOR_VERSION, .driver_flags = 0, .handle2 = NULL, .process_exit = NULL, .stop_select = NULL }; DRIVER_INIT(reverse_driver) { return &driver_entry; } 
Enter fullscreen mode Exit fullscreen mode

Elixir часть:

defmodule ReverseString do def start() do :ok = :erl_ddll.load_driver('./', 'reverse_driver') Port.open({:spawn, 'reverse_driver'}, [:binary]) end def reverse(port, string) when is_binary(string) do true = Port.command(port, string) receive do {^port, {:data, result}} -> result after 1000 -> {:error, :timeout} end end def stop(port) do Port.close(port) end end 
Enter fullscreen mode Exit fullscreen mode

Компиляция C-исходника:

gcc -std=gnu99 -shared -fPIC -o reverse_driver.so reverse_driver.c \ -I/usr/lib/erlang/erts-15.2.7/include/ # Путь до Erlang зависит от вашей системы 
Enter fullscreen mode Exit fullscreen mode

Результат:

iex(1)> port = ReverseString.start #Port<0.6> iex(2)> ReverseString.reverse(port, "hello") "olleh" 
Enter fullscreen mode Exit fullscreen mode

2. 🦀 Rust — безопасность и производительность с Rustler

Оптимальный метод: Rustler (специализированная обёртка над NIF)

Почему Rustler?

  • Полная безопасность памяти
  • Удобные макросы для работы с BEAM терминами
  • Автоматическая обработка ошибок
  • Поддержка асинхронных задач

Пример: Параллельная обработка данных

Добавляем в mix.exe Rustler (На данный момент актуальная версия - 0.36.1)

 defp deps do [ {:rustler, "~> 0.36.1"} ] end 
Enter fullscreen mode Exit fullscreen mode

Добавляем Rust-проект в Elixir

mix deps.get mix rustler.new This is the name of the Elixir module the NIF module will be registered to. Module name > RustUtils This is the name used for the generated Rust crate. The default is most likely fine. Library name (rustutils) > # Тут просто нажимаем Enter (Ну или переименуйте на более удобное название) 
Enter fullscreen mode Exit fullscreen mode
// lib.rs use rayon::prelude::*; #[rustler::nif] fn parallel_double(input: Vec<i64>) -> Vec<i64> { input.par_iter().map(|&x| x * 2).collect() } rustler::init!("Elixir.RustUtils"); 
Enter fullscreen mode Exit fullscreen mode

Elixir часть:

defmodule RustUtils do use Rustler, otp_app: :rust_utils, crate: "rustutils" def parallel_double(_list), do: :erlang.nif_error(:not_loaded) end 
Enter fullscreen mode Exit fullscreen mode

Результат:

RustUtils.parallel_double([1, 2, 3]) # => [2, 4, 6] 
Enter fullscreen mode Exit fullscreen mode

3. 🐍 Python — простота интеграции через Ports

Оптимальный метод: Ports

Почему Ports?

  • Полная изоляция процессов
  • Простота отладки
  • Доступ ко всему Python-экосистеме
  • Поддержка долгих операций (ML модели и т.д.)

Пример: Создание своей модели и интеграция с TensorFlow

Создаём модель

# create_model.py import tensorflow as tf import numpy as np model = tf.keras.Sequential([ tf.keras.layers.Dense(1, input_shape=(3,), use_bias=False) ]) model.set_weights([np.array([[1.0], [1.0], [1.0]])]) model.save("my_model.h5") print("✅ Model saved to my_model.h5") 
Enter fullscreen mode Exit fullscreen mode
#tensorflow_port import sys import json import numpy as np import tensorflow as tf import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' tf.get_logger().setLevel('ERROR') model = tf.keras.models.load_model('my_model.h5') def predict(data): try: if isinstance(data, str): data = json.loads(data) input_array = np.array(data, dtype=np.float32).reshape(1, 3) prediction = model.predict(input_array) return json.dumps({"status": "success", "result": prediction.tolist()}) except Exception as e: return json.dumps({"status": "error", "message": str(e)}) if __name__ == "__main__": for line in sys.stdin: line = line.strip() if not line: continue try: response = predict(line) sys.stdout.write(response + "\n") sys.stdout.flush() except Exception as e: error = json.dumps({"status": "error", "message": str(e)}) sys.stdout.write(error + "\n") sys.stdout.flush() 
Enter fullscreen mode Exit fullscreen mode

Elixir часть:

defmodule TensorflowPort do @timeout 5_000 def start do Port.open( {:spawn, "python3 tensorflow_port.py"}, [:binary, :use_stdio, :exit_status, :stderr_to_stdout, {:line, 1024}] ) end def predict(port, input_data) do input_data |> Jason.encode!() |> then(&Port.command(port, &1 <> "\n")) wait_for_response(port) end defp wait_for_response(port) do receive do {^port, {:data, {:eol, line}}} -> case Jason.decode(line) do {:ok, %{"status" => "success", "result" => result}} -> {:ok, result} {:ok, %{"status" => "error", "message" => msg}} -> {:error, msg} _ -> wait_for_response(port) end {^port, {:exit_status, status}} -> {:error, "Python process exited with status #{status}"} after @timeout -> {:error, :timeout} end end end 
Enter fullscreen mode Exit fullscreen mode

Результат:

Для работы программы нужно будет зайти в Python-окружение и оттуда запустить iex -S mix

(venv) iex(1)> port = TensorflowPort.start #Port<0.10> iex(2)> TensorflowPort.predict(port, [1,2,3]) {:ok, [[6.0]]} 
Enter fullscreen mode Exit fullscreen mode

4. 🐹 Go — эффективность через C-обёртки или gRPC

Оптимальные методы:

  • C-обёртки для NIF — когда нужна максимальная производительность
  • gRPC — для сложных взаимодействий и микросервисов

C-обёртка для Go кода (оптимально для производительности)

// fib.go package main import "C" func GoFib(n C.int) C.int { a, b := 0, 1 for i := 0; i < int(n); i++ { a, b = b, a+b } return C.int(a) } func main() {} 
Enter fullscreen mode Exit fullscreen mode

C-обёртка:

// c_src/go_nif.c #include <erl_nif.h> #include "libfib.h"  static ERL_NIF_TERM go_fib_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { int n; if (!enif_get_int(env, argv[0], &n)) { return enif_make_badarg(env); } return enif_make_int(env, GoFib(n)); } static ErlNifFunc nif_funcs[] = { {"go_fib", 1, go_fib_nif} }; ERL_NIF_INIT(Elixir.NifGo, nif_funcs, NULL, NULL, NULL, NULL) 
Enter fullscreen mode Exit fullscreen mode

Elixir часть:

defmodule NifGo do @on_load :load_nif def load_nif do nif_path = Path.expand("priv/go_nif", File.cwd!()) # Предварительная загрузка Go-библиотеки :erlang.load_nif(Path.expand("priv/libfib", File.cwd!()), 0) # Загрузка основной NIF-библиотеки :erlang.load_nif(nif_path, 0) end def go_fib(_n), do: raise("NIF not loaded!") end 
Enter fullscreen mode Exit fullscreen mode

Результат:

go build -buildmode=c-shared -o priv/libfib.so fib.go gcc -shared -fPIC \ -I/usr/lib/erlang/erts-15.2.7/include/ \ # Путь до Erlang зависит от вашей системы -I./priv \ -o priv/go_nif.so \ c_src/go_nif.c \ ./priv/libfib.so \ -Wl,-rpath,'$ORIGIN' LD_LIBRARY_PATH=./priv iex -S mix iex(1)> NifGo.go_fib(3) 2 
Enter fullscreen mode Exit fullscreen mode

⚠️ Если вам не хочется возиться с компиляцией и ABI, можно использовать gRPC или Ports вместо cgo. Это безопаснее, хоть и медленнее.

5. ⚡ Zig — Интеграция через Zigler

Оптимальный метод: Zigler (специализированная обёртка для Zig)

Почему Zigler?

  • Простота как у Rustler
  • Производительность как у C
  • Современные фичи языка (comptime, etc.)
  • Безопаснее чистого C

Пример: Быстрая обработка бинарных данных

Добавьте Zigler в mix.exe:

def deps do [ {:zigler, "~> 0.13.2", runtime: false} ] end 
Enter fullscreen mode Exit fullscreen mode

lib/nif_zig.ex:

defmodule NifZig do use Zig, otp_app: :zigler ~Z""" pub fn string_count(string: []u8) i64 { return @intCast(string.len); } pub fn list_sum(array: []f64) f64 { var sum: f64 = 0.0; for(array) | item | { sum += item; } return sum; } """ end 
Enter fullscreen mode Exit fullscreen mode

Результат:

iex(3)> NifZig.string_count("hello") 5 iex(4)> NifZig.list_sum([1.2,2.3,3.4,4.5]) 11.4 
Enter fullscreen mode Exit fullscreen mode

📊 Сводная таблица оптимальных методов

Язык Оптимальный метод Альтернативы Когда использовать
C NIF, Port Drivers Ports Максимальная производительность
Rust Rustler (NIF) - Безопасность + производительность
Python Ports gRPC Интеграция с ML/научными библиотеками
Go C-обёртки (NIF), gRPC Ports Использование Go-экосистемы
Zig Zigler (NIF) - Современная альтернатива C

😴 Заключение

Интеграция Elixir с нативным кодом открывает новые горизонты для разработчиков, позволяя сочетать преимущества BEAM (масштабируемость, отказоустойчивость) с производительностью и библиотеками других языков. В статье мы рассмотрели ключевые методы интеграции: NIF, Dirty NIF, Ports, Port Drivers, Rustler, Zigler и gRPC, а также их оптимальные сценарии использования.

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


От автора

Благодарю вас за внимание к данной статье! Надеюсь, вам было интересно узнать про способы интеграции других языков в Elixir. Из всех вариантов мне показался наиболее сложным Port Drivers, потому что создание одного такого драйвера само по себе превращается в настоящий квест, успешно завершённый лишь после нескольких часов подбора подходящих методов на C. В остальном, интеграция других языков в Elixir оказалась вовсе несложной, скорее даже увлекательной.

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

Для тех, кому интересно глубже погрузиться в мир технологий, архитектуры и разработки, приглашаю заглянуть в мой телеграм-канал 🖥, где я делюсь рецензиями на технические книги, полезными материалами по Elixir и не только 🤤

Top comments (0)