learn

Import/Include 중복 사용과 성능

Import/Include 중복 사용과 성능

"공통 라이브러리를 한 번만 import하면 성능이 좋아지지 않나?"라는 질문에서 출발한 노트.

결론부터

런타임 성능과는 무관하다. 세 언어 모두 중복 import/include가 런타임 오버헤드를 만들지 않는다. C만 빌드 속도에 영향이 있다.


Python

import는 처음 실행될 때 모듈을 로딩하고 sys.modules에 캐싱한다. 이후 같은 모듈을 import하면 캐시에서 참조만 가져올 뿐, 실제 로딩은 일어나지 않는다.

# a.py
import numpy as np  # 실제 로딩 발생

# b.py
import numpy as np  # sys.modules에서 참조만 가져옴, 비용 거의 0

따라서 __init__.py에 공통 import를 모아둬도 하위 모듈 파일들에서 자동으로 쓸 수 없고, 각 파일에서 여전히 직접 import해야 한다. Python 컨벤션은 각 파일에 명시적으로 import하는 것이다.

C

#include는 헤더 파일을 텍스트 그대로 복붙하는 전처리기 명령이다. 여러 .c 파일에서 같은 헤더를 include하면 각 translation unit마다 컴파일러가 반복 파싱한다.

이를 막기 위한 장치가 include guard#pragma once인데, 이는 같은 translation unit 안에서의 중복 include를 막는 것이고, 파일이 다르면 각자 파싱한다. 대형 프로젝트에서 헤더가 무거우면 빌드가 느려지는 문제가 실제로 존재했고, 이를 해결하기 위해 Precompiled Header(PCH) 가 나왔다.

어디까지나 컴파일 타임 얘기이고, 런타임 성능과는 무관하다.

Rust

use는 현재 scope에 이름을 바인딩하는 것이고, 실제 컴파일은 crate 단위로 한 번만 일어난다. 여러 파일에서 같은 것을 use해도 중복 컴파일 없다.

// a.rs
use std::collections::HashMap;

// b.rs
use std::collections::HashMap;  // 컴파일은 이미 됨, 그냥 이름 바인딩

Rust는 명시적 use를 강제하는 철학이라, wildcard use foo::*는 어디서 온 건지 추적이 어렵다고 경고하기도 한다.


비교 요약

| | 중복 사용 비용 | 실제 문제 | |---|---|---| | Python | 런타임 없음 (sys.modules 캐시) | 없음 | | C | 컴파일타임 있음 (헤더 반복 파싱) | 빌드 속도 (런타임 아님) | | Rust | 컴파일타임 없음 (crate 단위 빌드) | 없음 |