GN⁺: Elixir에 Python 내장하기, 문제없어요
(dashbit.co)- 최근 몇 년간, Elixir는 Nx (Numerical Elixir) 프로젝트를 통해 머신 러닝과 데이터 분야에서 역량 확장 중임
- Nx, Explorer, Axon, Bumblebee, Scholar 등의 프로젝트가 등장하여 Python과 R 생태계에서 배운 교훈을 기반으로 발전 중
- 초기에는 Python 라이브러리에 직접 의존하지 않기로 결정했는데, Elixir에 최적화된 설계 추구 및 Python 환경 설정의 복잡성 회피를 위해서였음
- 그런데, 요즘 이 분야에서 Elixir 도입을 주도하는 것은 Livebook 임
- Elixir와 Erlang의 강점을 기반으로 재현성, 분산 실행, 앱 개발의 최전선에 있는 노트북 플랫폼
- Livebook을 통해 Elixir 생태계에 처음으로 발을 들여놓으려는 팀과 기업들의 관심이 점점 더 커지고 있음
- 하지만 장애물이 있음
- Elixir와 Livebook을 인프라에 도입하려는 대부분의 회사는 이미 Python 기반의 워크플로, 패키지 및 리포지토리를 사용중
- 이 선택을 위해서 Elixir에서 동등한 패키지를 찾거나 처음부터 새로 작성해야 한다는 것을 의미하며, 데이터 스택에 Elixir를 추가하는 데 따르는 위험과 비용이 증가한다는 것을 의미
- 이를 해결하기 위해 Python 인터프리터를 Erlang VM 내에 내장하는 Pythonx 를 발표
Pythonx
- Pythonx는 Elixir와 Python 간의 자동 데이터 변환, 코드 평가, 가상 환경 관리 기능을 제공
- Optical Character Recognition(OCR) 수행을 위해
pytesseract
패키지 활용 가능 -
req
를 사용하여 이미지를 다운로드한 후,Pythonx.uv_init/1
호출을 통해 Python과 종속성 다운로드 및 초기화 -
Pythonx.eval/2
을 사용하여 Python 코드 실행 및 결과를 Elixir 문자열로 변환
내부 구조
- Python의 CPython 참조 구현은 다른 애플리케이션에 내장 가능
- Python 인터프리터의 핵심 기능이 C 라이브러리로 제공됨
- C/C++ 애플리케이션이 해당 라이브러리를 링크하고 API를 사용하여 코드 실행 및 객체 상호 작용 가능
- Elixir는 Erlang NIFs를 통해 C/C++와의 상호 운용성을 제공
- Pythonx는 NIFs를 활용하여 Python을 내장하며, 동일한 OS 프로세스에서 동작
- Python과 Elixir 간의 데이터 전달이 효율적으로 이루어짐
Livebook의 다중 언어 지원
- Pythonx를 기반으로 Livebook에서 Python 지원 추가 진행 중
- 동일한 노트북에서 Elixir와 Python이 상호 작용 가능해짐
- Livebook이 Python 및 종속성을 자동으로 설치하고, Elixir와 Python 변수 간의 변환을 관리
- 재현 가능한 환경을 보장
- 현재 코드 완성, 문서화 등 추가 작업 진행 중이며, Livebook nightly 다운로드 및 사용 가능
사용 시 고려사항 및 대안
- Pythonx의 주요 목적은 Livebook 및 스크립트 내에서 Python 워크플로우를 통합하는 것임
- Python의 전역 인터프리터 잠금(GIL)로 인해 여러 Elixir 프로세스에서
Pythonx
호출 시 동시성 제한 가능성 존재함 - 단일 Elixir 프로세스에서 호출하거나, Python 라이브러리가 동시 호출을 처리할 수 있는지 확인 필요함
- 대안으로
System.cmd/3
또는 Port를 사용하여 여러 Python 프로세스 관리 가능함 - AI 워크플로우의 경우 Bumblebee를 통해 사전 학습된 모델 실행 가능함
- Ortex를 활용하여 ONNX 모델 실행 가능함
- LLM의 경우 서드파티 API 사용 또는 온프레미스에서 Llama.cpp Docker 컨테이너 실행 가능함
- HTTP 기반 인터페이스 활용 시 Elixir의 Instructor 및 LangChain 등의 도구 활용 가능함
Fine 프로젝트
- Pythonx는 NIFs를 사용하여 구현됨
- NIFs는 C로 구현된 Elixir 함수이며, 많은 보일러플레이트 코드 요구됨
- 메모리 관리 및 오류 처리 복잡성이 존재
- 이를 해결하기 위해 C++ 기반의 Fine 라이브러리 개발됨
- Fine은 데이터 구조 변환 자동 처리, 리소스 객체 안전 관리, 예외 발생 기능을 제공
- NIF 작성 시 코드의 양을 크게 줄일 수 있음
결론
- Numerical Elixir 프로젝트의 목표는 Elixir가 데이터 및 머신 러닝 생태계에서 독자적인 정체성을 갖도록 하는 것임
- 이제 상호 운용성을 주요 목표로 삼고 있음
- Pythonx는 Elixir에 Python을 내장하여, 두 언어 간의 투명한 상호 변환을 가능하게 함
Hacker News 의견
-
Livebook의 기능이 매우 멋있음. Elixir에서 C++ NIFs를 통해 CPython을 직접 호출하고 Elixir-native 데이터 구조를 반환하는 점이 깔끔함
- 프로덕션 서버에서는 Pythonx 사용이 다소 위험할 수 있음. Elixir 앱과 동일한 OS 프로세스에서 실행되기 때문에 Elixir/BEAM 앱의 강력한 실패 복구 기능을 우회하게 됨
- 일반적으로 Elixir 앱은 자체 BEAM 프로세스의 실패를 우아하게 처리할 수 있는 감독 트리를 가지고 있으며, 이는 Elixir, Erlang, Gleam 같은 언어의 큰 장점임
- NIFs를 사용할 경우, Pythonx에서 처리되지 않은 예외가 발생하면 전체 OS 프로세스와 모든 BEAM 프로세스를 중단시킬 수 있음
- Rustler는 Elixir에서 Rust를 위한 인기 있는 NIF 래퍼로, NIFs가 매우 유용한 경우도 있지만, 전체 앱을 중단시킬 수 있는 위험을 고려해야 함
- Ports를 사용하여 Python이나 Rust 같은 다른 네이티브 코드를 실행하는 것이 이 점에서 덜 위험함
-
Elixir 커뮤니티의 "잘 알려진" 사람들이 이러한 접근 방식을 지지하고 적극적으로 개발하는 것을 보는 것이 좋음
- VM과 런타임이 다른 언어와 기술을 조율하는 데 매우 적합하여 표준 트랙과 오프로드 트랙이 있는 것처럼 느껴짐
- 오프로드 "위험해 보이는" 아이디어와 안전한 실행의 차이는 종종 작업량에 불과하지만, 런타임은 이를 장려함
- NIF이기 때문에 약간의 위험이 있지만, 별도의 BEAM 인스턴스를 생성하고 이를 통해 분산할 수 있음
-
NIFs 사용의 안전성 문제를 지적한 다른 댓글들이 있음
- Erlang VM 스케줄러는 NIF를 선점할 수 없으므로, 장시간 실행되는 Python 호출이 VM을 중단시킬 위험이 있음
- GIL이 동시 Python 실행을 방지하지만, Erlang 호출자가 여러 Python 인터프리터를 실행할 수 있어 Ports에서는 문제가 되지 않음
-
매우 유익한 기사임. Pythonx가 단순한 서브프로세스 호출이 아니라 동일한 프로세스에서 실행된다는 점을 명확히 언급한 것이 좋음
- Elixir에서 Python에 정의된 함수를 호출하는 예제가 추가되었으면 좋겠음
-
Elixir가 AI 전쟁에서 JavaScript와 Python보다 더 적합함에도 불구하고 뒤처져 있는 것을 보게 되어 기쁨
- Elixir의 ML 기반을 처음부터 확장하려는 초기 결정을 좋아하지만, 빠르게 발전하는 Python 라이브러리를 활용할 수 있는 방법이 생긴 것도 좋음
-
Python에서 Elixir/Erlang 생태계로 진입하는 것이 너무 어렵게 느껴졌지만, Pythonx로 점진적인 학습이 훨씬 더 가능해 보임
- Python의 GIL 문제에 대해 자유 스레딩을 실험했는지 궁금함
-
Elixir에는 Python에 있었으면 하는 몇 가지 기능이 있음
- 아톰, 대부분의 것이 매크로임, 파이프 |>, 진정한 불변성, 감독 트리 덕분에 진정한 병렬성과 동시성, 핫 코드 리로딩, 내결함성
-
Elixir에 깊이 관여하고 Python을 많이 사용했던 사람으로서 매우 실용적이라고 생각함
- C++ NIFs를 쉽게 만드는 Fine 라이브러리에 더 관심이 있음
-
이 프로젝트와 블로그 게시물이 나를 위해 만들어진 것처럼 느껴짐. 사용해보고 싶음, 고마움