더 작고 일관된 난수 API를 위해 rand를 포크한 이유
요약
Rust의 rand 크레이트를 포크하여 API 일관성과 성능을 최적화한 urandom 라이브러리를 소개합니다. 복잡한 트레이트 구조를 하나의 Random 구조체로 통합하고, 특정 알고리즘에 최적화된 설계를 통해 기존 rand 대비 높은 처리량을 달성했습니다.
핵심 포인트
- 여러 트레이트에 분산된 API를 하나의 Random 구조체로 통합하여 발견성 향상
- Rng 트레이트를 봉인하여 내부 최적화 및 알고리즘 특수화 가능
- Xoshiro256 활용 및 비편향 구현 통합으로 rand 대비 약 31% 성능 향상
- 범용 확장성 대신 사용 편의성과 실행 속도에 집중한 설계
- Rust의 대표 난수 크레이트
rand
는 일상적인 연산이 여러 특성에 흩어져 있어, 더 작은 공개·구현 표면과 일관된 사용 경험을 갖춘 urandom을 개발함
- 고수준 연산을 하나의
Random
구조체에 모으고 Rng
특성을 봉인해, 임의 생성기 지원보다 API 발견성과 내부 최적화를 우선함
- 새로운 난수 알고리듬을 도입하지 않고 Xoshiro256의 출력 함수를 용도별로 선택해, 1,000개
f64
생성 벤치마크에서 rand
0.10.2보다 약 31% 높은 처리량을 기록함
- 균등 정수 표본 추출은 임계값을 지연 계산하는 하나의
비편향 구현으로 재사용·일회성 경로를 통합했으며,500..20_000
범위 벤치마크에서 rand
의 두 경로보다 빨랐음
- 명시적 시드의 원시 출력은 지원 아키텍처와 SemVer 호환 릴리스에서 재현성을 보장하지만,
임의 생성기 연결과rand
의 방대한 분포·서드파티 통합 생태계는 포기함
하나로 모은 Random
API
rand
의 유용한 연산은 여러 특성에 흩어져 있음
- 난수 범위 생성에는
RngExt
, 시퀀스 선택에는 IndexedRandom
, 섞기에는 SliceRandom
이 필요함
rand
0.10은 일회성 호출을 위한 rand::random_range
같은 루트 수준 도우미를 제공함
-
RNG 핸들을 유지하거나 선택·섞기 같은 시퀀스 연산을 사용하려면 여전히 여러 특성의 메서드를 찾아야 함
-
prelude로 가져오기를 줄여도 확장 메서드가 RNG, 슬라이스, 반복자 중 어느 타입에 적용되는지 알아야 하므로 IDE 자동 완성만으로 찾기 어려움
-
urandom은 고수준 소비자 API를 하나의
Random
래퍼 구조체에 배치함
urandom::new()
로 Random<urandom::rng::Xoshiro256Rng>
를 생성함
uniform
, choose
, shuffle
을 같은 객체에서 호출할 수 있음
- 자동 완성으로
random
, uniform
, chance
, choose
, shuffle
, sample
등을 확인할 수 있음
- 모두 고유 메서드이므로 고수준 확장 특성을 찾거나 가져올 필요가 없음
확장성 대신 최적화를 택한 봉인된 Rng
rand
는 저수준 RNG 특성을 공개 확장 지점으로 취급하지만, urandom
의 Rng
특성은 봉인되어 지원 생성기를 크레이트 내부에서 선택하고 구현함
- 임의 생성기를
Random
에 연결할 수 없음
- 새 생성기를 추가하려면
urandom
자체를 변경해야 함
-
더 나은 알고리듬이 목적이라면 현재 역할별 기본 선택으로 Xoshiro256과 ChaCha가 이미 자리 잡고 있으며, 권장 사항도 천천히 바뀜
-
더 나은 선택지가 생기면 향후 메이저 릴리스에서 채택할 수 있음
-
다른 프로젝트·프로그래밍 언어·레거시 알고리듬·특수 하드웨어·시뮬레이션 전용 생성기와 호환하려면 생성기만 같아서는 부족함
-
균등 표본 추출과 섞기 등 관련 알고리듬까지 같아야 하므로 전체 계약을 구현한 전용 구현이 더 적합함
-
봉인된 특성 덕분에 알 수 없는 생성기와 예외 상황을 위한 구현 계약을 설계·문서화하지 않고
urandom
에 필요한 원시 연산만 추가할 수 있음
- 생성기와 알고리듬을 서로 맞춰 특수화할 수 있어
rand
에서는 사용할 수 없는 일부 최적화가 가능함
- 대부분의 애플리케이션에서는 새 PRNG 구현보다
엔트로피 선택이 더 유용함 - 구체적인 생성기는 네이티브
from_seed
생성자를 공개함
ChaCha12Rng::from_seed(seed)
처럼 명시적 시드를 사용한 Random
을 만들 수 있음
- 임의 RNG 구현은 받지 않지만 고급 사용자가 필요로 할 것으로 예상되는 확장 지점은 유지함
같은 알고리듬에서 얻은 성능 향상
urandom
은 새로운 난수 생성 알고리듬을 사용하지 않음
- 64비트 시스템에서 비암호학적 용도의
urandom::new()
와 rand::rngs::SmallRng
은 같은 Xoshiro256 계열을 사용함
- 암호학적 용도의
urandom::csprng()
와 rand::rngs::StdRng
은 ChaCha12를 사용함
- 편의 함수
rand::rng()
의 내부 생성기도 ChaCha12임
rand
의 생성기 인터페이스는 정수 워드와 바이트 채우기를 제공하므로 f64
가 필요한 분포도 전체 u64
부터 요청함
urandom::Rng
은 next_u32
, next_u64
뿐 아니라 next_f32
와 next_f64
도 제공함
-
부동소수점 난수는 전체 워드보다 적은 난수 비트가 필요함
-
생성기는 이 메서드들을 더 저렴한 출력 함수로 재정의할 수 있음
-
Xoshiro 구현은 상태 전이를 공유하면서 출력 경로를 구분함
u64
에는 Xoshiro256++를 유지함
u32
와 부동소수점에는 상위 비트가 해당 용도에 맞게 설계된 더 빠른 Xoshiro256+를 사용함
urandom
1.0과 rand
0.10.2로 각각 1,000개의 난수를 생성한 마이크로벤치마크 결과는 다음과 같음
- Xoshiro
u64
: 양쪽 모두 814ns
- Xoshiro
u32
: rand
836ns, urandom
788ns
- Xoshiro
f64
: rand
1,033ns, urandom
788ns
- ChaCha12
f64
: rand
2,199ns, urandom
2,011ns
- Xoshiro
f64
의 종단 간 처리량은 약 31% 높고 실행 시간은 24% 짧았지만, 동일한 작업을 수행하는 u64
경로는 사실상 동률이었음
- ChaCha12는
next_f64
를 재정의하지 않아 성능이 대체로 비슷함
- 정확한 시간은 머신과 컴파일러에 따라 달라지며, 자세한 조건은 전체 벤치마크 노트에서 확인할 수 있음
하나로 통합한 균등 표본 추출 경로
- 정수를 범위 길이로 단순 나머지 연산하면
편향이 생기므로, 올바른 균등 정수 표본 추출은 생성기 출력 일부를 거부해야 함 - 정확한 거부 임계값 계산에는 비용이 큰 나머지 연산이 필요함
- 표본 추출기를 반복 사용한다면 초기 설정 비용으로 감당할 수 있음
- 값 하나만 생성할 때는 이 비용이 상대적으로 커짐
rand
는 이러한 차이를 UniformSampler
특성으로 노출함
- 생성된
UniformInt
는 임계값을 미리 계산해 편향 없이 표본을 추출함
Rng::random_range
는 초기 설정을 피하려고 별도의 sample_single
또는 sample_single_inclusive
훅을 사용함
- 기본 기능에서는 일회성 단축 경로가 조금 편향된 두 번째 알고리듬을 사용함
- 선택적
unbiased
기능은 이를 더 복잡한 반복 버전으로 교체함
urandom
은 임계값을 지연 계산해 재사용 및 일회성 범위 모두에 하나의 비편향 곱셈·거부 구현을 사용함
- 별도 메서드나 두 번째 알고리듬, 선행 설정 비용, 편향된 고속 경로 없이 동일한 구현으로 재사용 분포와 일회성 범위를 처리함
500..20_000
범위에서 1,000개를 추출한 벤치마크 결과는 다음과 같음
- 재사용
UniformInt
: rand
1,098ns, urandom
950ns
- 일회성 범위:
rand
1,079ns, urandom
942ns
rand
결과는 기본 기능 기준이므로 더 빠른 일회성 행도 약간 편향된 경로인 반면, urandom
은 비편향 상태로 두 경로보다 빨랐음
릴리스와 아키텍처를 아우르는 재현성
urandom
은 재현성을 공개 계약의 일부로 취급함
-
같은 명시적 시드와 같은 저수준 RNG 호출 순서가 주어지면 결정론적 생성기의 원시 출력이 유지됨
-
지원 아키텍처와 SemVer 호환 릴리스 전체에서 안정성을 보장함
-
64비트 서버와 32비트 WebAssembly 클라이언트가 재생을 위한 동일한 생성기 기반을 사용할 수 있음
-
이 호환성을 유지하기 위해 32비트 아키텍처에서는 성능을 희생함
rand
의 재현성 정책보다 강한 보장임
rand
의 이식 가능한 생성기와 표본 추출 알고리듬은 마이너 릴리스에서 출력이 달라질 수 있음
SmallRng
과 StdRng
은 명시적으로 이식 가능하지 않으며 플랫폼이나 라이브러리 릴리스에 따라서도 바뀔 수 있음
선택의 대가와 적용 기준
urandom
은 일반 연산을 Random
에 모아 확장 특성 없이 쉽게 찾을 수 있게 함
- 생성기와 분포를 함께 설계해 더 저렴한 Xoshiro 출력 경로와 하나의 비편향 균등 표본 추출 경로를 구현함
- 명시적으로 시드가 지정된 생성기의 안정적인 원시 스트림은
결정론적 게임과 시뮬레이션에 활용할 수 있음 - 대신 임의 생성기를 가져올 수 없으며,
rand
가 제공하는 더 큰 분포 목록과 서드파티 통합 생태계도 갖추지 못함
- 광범위한 생태계가 필요하면
rand
가 적합하고, 작은 API 표면·발견성·통합된 최적화·강한 재현성 정책을 선호하면 urandom
을 선택할 수 있음
- 패키지는 crates.io, API 문서, GitHub 소스에서 확인할 수 있음
댓글과 토론
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기