-
Moore의 법칙이 한계에 봉착하며, 단일 코어 고속화에서 다중 코어, 병렬 처리 중심으로 하드웨어가 진화함
-
병렬 처리는 데이터 병렬성, 모델 병렬성, 파이프라인 병렬성 등 여러 형태로 구분되며, 현대 딥러닝 시스템에서 혼합적으로 사용됨
-
SIMD(명령어 수준 데이터 병렬성), 스레드/코어 병렬성, GPU 대량 병렬 등 다양한 계층에서 병렬화가 이뤄짐
-
병렬 처리를 위한 언어·라이브러리·도구는 대부분 기존 순차 언어에 '붙여진' 확장형이 많아, 병렬성이 언어에 네이티브로 통합되는 흐름(Mojo 등)이 주목받음
-
캐시 라인 공유(불필요한 상호작용) 최적화, 효율적 메모리 분할, 자동 벡터화 등 실질적 성능 최적화가 중요한 과제임
병렬성의 동기와 하드웨어 진화
- 초기에는 트랜지스터 소형화와 클럭 상승으로 성능이 자연스럽게 향상됐으나, 발열/제조 공정 한계로 물리적 한계에 도달함
- 이후 멀티코어 구조가 표준이 되었으며, 한 CPU에 수~수백 개의 코어가 탑재됨
병렬성의 일반적 형태
-
데이터 병렬성: 동일 연산을 다수 데이터에 동시 적용(예: 벡터 합 연산)
-
모델 병렬성: 하나의 모델을 여러 디바이스에 분산 배치
-
파이프라인 병렬성: 계산을 여러 단계로 분할, 각 단계가 동시에 동작
SIMD(단일 명령 다중 데이터)와 벡터화
-
SIMD는 한 명령어로 여러 데이터(벡터)를 처리하는 방식으로, ARM NEON, x86 SSE/AVX 등 다양한 ISA에서 지원
-
C/C++ 인트린식을 통해 벡터 연산을 명시적으로 제어 가능, 컴파일러의 자동 벡터화도 지원하지만 한계가 있음
- 실전에서는 벡터 길이만큼 반복 처리 후, 남은 데이터는 스칼라 연산으로 보정
CPU에서의 병렬화
-
스레드를 활용해 멀티코어에서 병렬 실행, 언어별 API와 OS 스케줄러 지원
- 스레드 생성/소멸 비용이 크므로, 데이터 크기 대비 적절한(코어 수와 유사한) 스레드 개수로 작업 분할이 효율적
-
캐시 라인 'false sharing'(다른 스레드가 같은 캐시 라인 내 독립 변수 접근 시 성능 저하) 최적화가 중요, C++17의
std::hardware_destructive_interference_size
등 활용
- 각 스레드가 별도의 데이터 영역을 쓰도록 패딩/정렬 처리 필요
GPU에서의 병렬화
- GPU는 수천 개의 작은 코어를 통해 대규모 데이터 병렬 처리에 특화
-
CUDA/OpenCL: 커널 함수를 수십~수만 개의 스레드/블록 단위로 실행, 내부적으로는 SIMT(싱글 명령 다중 스레드) 모델
-
워크 그룹/워프 단위 동작, 분기(branch divergence) 최소화가 성능에 매우 중요
-
메모리 계층 구조: 스레드 레지스터, 블록 공유 메모리, 전체 글로벌 메모리 등 계층적 최적화 필요
Triton: 파이썬 기반 GPU 커널 DSL
-
Triton은 파이썬에 내장된 DSL로, JIT 컴파일 및 다중 백엔드(MLIR/LLVM/PTX 등) 지원
- 커널 코드를 고수준 파이썬으로 작성, 자동 병렬화·분할·마스킹 등 지원
- NVIDIA cuDNN 수준 대비 75~90% 성능을 내면서, 개발 복잡도 대폭 감소
병렬성의 네이티브 언어화: Mojo
-
Mojo는 LLVM/MLIR 개발자 Chris Lattner가 만든 새로운 언어로, 병렬성과 하드웨어 특화 컴파일을 언어 수준에서 지원
- SIMD 벡터 타입, 벡터화 함수, 호스트/디바이스 메모리 구분 등 타입 시스템과 언어 구조에 병렬성이 내장
- 파이썬 스타일의 루프도 자동 벡터화, 명시적 저수준 제어 없이 성능 확보 가능
결론 및 전망
- 현대 병렬 프로그래밍은 다양한 하드웨어와 병렬성 모델의 조합으로 이뤄지며, 언어 자체의 지원이 점차 중요해짐
- Mojo, Triton, JAX 등 차세대 병렬 언어·도구의 부상으로, 병렬화가 더 직관적이고 생산적으로 진화하는 중
- 병렬 프로그래밍은 하드웨어 구조, 메모리 최적화, 언어 지원이 유기적으로 결합되어야 실제 성능을 극대화할 수 있음