본문으로 건너뛰기

[uv] uv의 패키지 설치 성능 최적화: 불필요한 site-packages 스캔 제거

PR 링크: astral-sh/uv#20119 상태: Merged | 변경: +122 / -5

들어가며

Python 패키지 관리자 uv는 압도적인 속도로 많은 개발자에게 사랑받고 있습니다. 하지만 기존 uv pip install은 설치를 시작하기 전, 환경 내의 모든 site-packages를 인덱싱하는 과정을 거쳤습니다. 이는 설치 결과에 영향을 주지 않는 패키지들까지 메타데이터를 읽어야 함을 의미하며, 설치된 패키지가 많아질수록 성능 저하의 원인이 되었습니다. 본 PR은 특정 조건(예: --reinstall 또는 pylock.toml 사용 시)에서 이 스캔 과정을 지연시키고, 필요한 패키지만 선택적으로 인덱싱하도록 개선하여 성능을 크게 향상했습니다.

코드 분석

1. crates/uv-installer/src/site_packages.rs: 지연 로딩 및 필터링 구현

가장 핵심적인 변경은 SitePackages 구조체에 필터링 기능을 추가한 것입니다. 이제 전체를 스캔하는 대신, 필요한 패키지 이름만 전달하여 인덱싱할 수 있습니다.

// Before: 항상 전체 스캔
pub fn from_interpreter(interpreter: &Interpreter) -> Result<Self> { ... }

// After: 필터링된 스캔 지원
fn from_interpreter_with_filter(
    interpreter: &Interpreter,
    package_names: Option<&FxHashSet<&PackageName>>,
) -> Result<Self> { ... }

또한, 메타데이터 파일을 직접 열지 않고도 파일명만으로 패키지 이름을 추론하는 installed_dist_name 함수를 도입하여 I/O 비용을 최소화했습니다.

2. crates/uv/src/commands/pip/install.rs: 설치 로직의 최적화

pip_install 함수 내에서 site_packages를 초기화하는 시점을 제어합니다. modifications가 충분하고(Sufficient), pylock을 사용하거나 전체 재설치(Reinstall::All)를 수행하는 경우, 초기 스캔을 None으로 지연시킵니다.

// 설치 시점에 필요한 패키지만 골라내어 스캔
let site_packages = match site_packages {
    None => SitePackages::from_environment_for_packages(
        &environment,
        resolution.distributions().map(Name::name),
    )?,
    Some(site_packages) => site_packages,
};

왜 이게 좋은가

이 최적화는 '불필요한 I/O를 줄이는 것'이 성능의 핵심임을 다시 한번 보여줍니다. 특히 대규모 프로젝트 환경에서 그 효과가 극명하게 나타납니다.

  • 성능 수치: 2,000개의 패키지가 설치된 환경에서 dry-run 또는 계획 단계의 경우 기존 대비 21.5%의 속도 향상을 보였습니다.
  • 교훈: 설치나 빌드 도구에서 '전체 환경 스캔'은 확장성(Scalability)을 저해하는 병목 지점입니다. 의존성 해결 단계에서 필요한 정보만 선별적으로 가져오는 'Lazy Loading' 전략을 적용하면, 환경의 크기와 관계없이 일관된 성능을 유지할 수 있습니다.

이번 변경은 uv가 대규모 모노레포나 복잡한 의존성 환경에서도 안정적인 성능을 제공할 수 있도록 돕는 중요한 이정표가 될 것입니다.

참고 자료

⚠️ 알림: 이 분석은 AI가 실제 코드 diff를 기반으로 작성했습니다.

댓글

관련 포스트

PR Analysis 의 다른글