[Rust] iterator ์ฑ๋ฅ ๋ฒค์น
iterator๋ Rust๊ฐ ์ ๋ ดํ ์ถ์ํ๋ผ๊ณ ์๋ํ๋ ์ฃผ์ ์ฌ๋ก๊ฑด ์ค ํ๋๋ค. zero cost abstractions๋ผ๊ณ ๋ถ๋ฅธ๋ค.
๊ทผ๋ฐ ์ ๋น์ฉ์ผ๋ก ์ต์ ํ๊ฐ ๋๋ค๊ณ ๋ ์ฃผ์ฅํ๋๋ฐ, ๊ทธ ๋ฐฉ์๊ณผ ์๋ฆฌ์ ๋ํด์๋ ๋ฑํ ๋๋ ทํ ์ค๋ช
์ ํด์ฃผ์ง๋ ์๋๋ผ.
๊ทธ๋ฌ๋ฉด ์ง์ง๋ก iterator๊ฐ for ๋ฃจํ์ ๋๋ฑํ ์๋๋ฅผ ๋ด๋๊ฑธ๊น? ๊ถ๊ธํด์ ์คํ๋ถํฐ ํด๋ดค๋ค.
pub struct Timer {
start: std::time::Instant,
}
impl Timer {
pub fn new() -> Timer {
Timer {
start: std::time::Instant::now(),
}
}
pub fn elapsed(&self) -> std::time::Duration {
self.start.elapsed()
}
pub fn elapsed_as_millis(&self) -> u128 {
self.elapsed().as_millis()
}
pub fn elapsed_as_secs(&self) -> u64 {
self.elapsed().as_secs()
}
}
fn do_iterator_test(input: Vec<i32>) -> Vec<f64> {
input.iter().map(|&x| x as f64).collect()
}
fn do_loop_test(input: Vec<i32>) -> Vec<f64> {
let mut result = Vec::new();
result.reserve(input.len());
for i in 0..input.len() {
result.push(input[i] as f64);
}
result
}
fn main() {
const N: usize = 1_000_000_000;
let mut loop_test = vec![1; N];
let mut iter_test = vec![1; N];
for i in 0..N {
loop_test[i] = i as i32;
iter_test[i] = i as i32;
}
let timer = Timer::new();
let sum_1 = do_loop_test(loop_test);
println!("loop: {}ms", timer.elapsed_as_millis());
let timer = Timer::new();
let sum_2 = do_iterator_test(iter_test);
println!("iter: {}ms", timer.elapsed_as_millis());
assert_eq!(sum_1, sum_2);
}
๊ทธ๋ฅ i32 ๋ฒกํฐ๋ฅผ f64 ๋ฒกํฐ๋ก ์นํํ๋ ๊ฐ๋จํ ์ฝ๋๋ฅผ loop ๋ฒ์ ๊ณผ iterator ๋ฒ์ ์ผ๋ก ๊ฐ๊ฐ ์์ฑํด๋ดค๋ค.
๋๋ ์ฑ๋ฅ์ด ๋น์ทํ๊ฒ ๋์ค๊ฑฐ๋ ์ผ๋ฐ ๋ฃจํ๊ฐ ๊ทผ์ํ๊ฒ ๋น ๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์์ํ๋ค.
์ฒซ๋ฒ์งธ ํ ์คํธํ๊ฒฝ์ Ubuntu 22, x86_64, RAM 32GB์๋ค.
ํ์ง๋ง ์์ธ๋ก iterator์ ์ฒ๋ฆฌ์๋๊ฐ ํจ์ฌ ๋นจ๋๋ค.
release๋ก ๋น๋ํด๋ ๊ทธ๋ ๊ณ , ์คํ ์์๋ฅผ ๋ฐ๋๋ก ๋ฐ๊ฟ๋ ๋ค๋ฆ์ด ์์๋ค. ์บ์์ ์ํฅ๋ ์๋๋ผ๋ ๊ฒ์ด๋ค.

fn do_loop_test(input: Vec<i32>) -> Vec<f64> {
let mut result = vec![0_f64; input.len()];
let mut i = 0;
while i < input.len() {
result[i] = input[i] as f64;
i += 1;
}
result
}
vector push๋ฅผ ์ ๊ฑฐํ๊ณ ๋ฏธ๋ฆฌ ํ ๋นํ๋ ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝํ๋ ์ข ๋๋ฑํด์ก์ผ๋, ๊ทธ๋๋ ํญ์ iterator๊ฐ ๋ฏธ์ธํ๊ฒ ๋นจ๋๋ค.
๊ทธ๋ผ ๋ค๋ฅธ ํ๋ซํผ์์๋ ์ด๋จ๊น?
Mac ํ๊ฒฝ์์๋ ํ
์คํธํด๋ดค๋ค.
์คํ์ M2 Pro Ventura 13, RAM 16GB์๋ค.

Mac์์์ ๋ฒค์น๋งํฌ ๊ฒฐ๊ณผ๋ ์ข ๋ ํผ๋์ค๋ฌ์ ๋ค.
iter ๋ฒ์ ์ ๋จผ์ ์คํํ๋ฉด iter๊ฐ ๋ ๋น ๋ฅด๊ณ , loop ๋ฒ์ ์ ๋จผ์ ์คํํ๋ฉด loop๊ฐ ๋ ๋นจ๋๋ค. ๊ทผ๋ฐ ์๋ฌดํผ ์์ฒญ ํฐ ์ฐจ์ด๊น์ง ๋ฒ์ด์ง์ง๋ ์์๋ค.
LLVM-IR ๊น๋ณด๊ธฐ
์ด์ ๋ธ๋ฆฌ ์์ค๊น์ง ๊ฐ๊ธฐ์๋ ๋๋ฌด ๊ณ ํต์ค๋ฝ๊ณ , llvm์ด ์๊ธฐ๋ค ๋ง์๋๋ก ์ต์ ํ๋ฅผ ๊ฐํ๋ ๊ฒ๋ ์๊ธฐ ๋๋ฌธ์ Rust๊ฐ ์ต์ ํ๋ฅผ ํ๋ ๋ถ๋ถ์ ๋ณด๊ณ ์ถ๋ค๋ฉด llvm-ir์ ๊น๋ณด๋ ๊ฒ์ด ๊ฐ์ฅ ๋ช ํํ ๋ฐฉ๋ฒ์ด๋ค.
์ฐ์ llvm-ir์ ๋ฝ์๋ดค๋ค.
๊ทธ๋ฌ๋ฉด ์ด๋ ๊ฒ ์ฃผ์์ด ์น์ ํ๊ฒ ๋ฌ๋ ค์๊ธฐ ๋๋ฌธ์ ๋ณด๋ ๊ฒ์ด ๊ทธ๋ ๊ฒ ์ด๋ ต์ง๋ง์ ์๋ค.
๋ฃจํ ๋ฒ์ ํจ์์ ๊ฒฝ์ฐ์๋ ๋ค์๊ณผ ๊ฐ์ด ๊ณ ์ ์ ์ธ ํํ๋ก ๋ฃจํ ๊ตฌ๋ฌธ์ ๊ตฌ์ฑํ๋ค.
i ๋ณ์๋ฅผ 0์ผ๋ก ๊น๊ณ
๋ฐ๋ณต์ ์ํ length ๊ฐ์ ํ ๋นํ๊ณ
๋บ๋บ๋๋ฉด์ ์์ ๋๋ง bb5 ๋ ์ด๋ธ๋ก ์ด๋ํ๋ค.
์ข ์ฅํฉํ๊ธด ํ๋ฐ, result[i] = input[i] as f64๊ฐ ๋ณํ๋ ๊ฒฐ๊ณผ๋ผ๊ณ ๋ณด๋ฉด ๋๋ค.
์ค๋ฒํ๋ก ์ฒดํฌ๋ ํ๊ณ , ๋ฐ์ด๋ ์ฒดํฌํด์ ํจ๋ ํธ๋ค๋ง์ ํ๋ ๊ฒ๋ ์๊ณ , ๋ญ๊ฐ ์ธ์คํธ๋ญ์
์ด ๋ง์๊ฒ ๊ทธ๋ฅ ๋ด๋ ๋๊ปด์ง ๊ฒ์ด๋ค.
๊ทธ์ ๋ฐํด iterator๋ก ์์ฑ๋ ์ฝ๋๋

๋น๊ต์ ๊ฐ๋จํ๋ค.
๋ฐ์ด๋ ์ฒดํฌ๋ ์๊ณ ?, iteration core ํจ์๋ฅผ 2๊ฐ ํธ์ถํ๋ ์ฝ๋๋ก ์์ฑ์ด ๋๋ค.
iterator ์ฝ๋์ ๊ฒฝ์ฐ์๋ ๋ฐ๋ณต์ ํํ๊ฐ ์ ํํ๋ ์ฑ๋ก ๊ณ ์ ๋์ด์๋ค๋ณด๋ ์ข๋ ๊ฐ๊ฒฐํ๊ณ ๊ณผ๊ฒฉํ ํํ๋ก ์ต์ ํ๊ฐ ๊ฐ๋ฅํ ๊ฒ ๊ฐ๋ค.
๋ฌผ๋ก ์ธ์คํธ๋ญ์ ์ด ๋ง๋๋ผ๋ llvm์ด ์์์ ์ต์ ํ๋ฅผ ํด์ค ์๋ ์์ง๋ง, ์ด ์ ๋๋ก ์ฐจ์ด๊ฐ ๋๋ค๋ฉด ๊ฒฐ๊ณผ์๋ ์ ์๋ฏธํ ์ฐจ์ด๊ฐ ๋ฐ์ํ ์ ์์ ๊ฒ์ด๋ค. ์์ ๋ณ์ ํ๋๋ง ์์ด๋ ๋ฌด์ธ๊ฐ ๋์ ์ํฅ์ ์ค ์ ์๋ค๋ฉด ์ต์ ํ ์๋จ์ ํ๋ ํฌ๊ธฐํ ์ ์๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
filter์ถ๊ฐํด๋ณด๊ธฐ
์์์ ํ ์คํธํ๋ ์ฝ๋๋ ํ์ ๋ณํ ์ ๋๋ง ํ๋ ์์ฃผ ๊ฐ๋จํ ์ฝ๋์๋ค. ๊ทธ๋ฌ๋ฉด ์ฒด์ด๋์ ์ข๋ ๋ํด๋ณด๋ฉด ์ด๋จ๊น?
map ํ์ filter๋ง ํ๋ฒ ๋ํด๋ณด๋ ํํ๋ก ์ฝ๋๋ฅผ ๋ณ๊ฒฝํด๋ดค๋ค.
์ด ๊ฒฝ์ฐ์๋ iteration์ด ์ฝ๊ฐ ๋๋ฆฐ ์ ๋๋ก ์ต์ ํ๊ฐ ๋์๋ค.
ํ
์คํธ ํ๊ฒฝ์ Mac M2๋ค.
ํ์ง๋ง ์ด ๋ฒ์ ์ iterator ์ฝ๋์๋ ์ฌ์ค ์กฐ๊ธ ๋นํจ์จ์ ์ธ ๋ถ๋ถ์ด ์๋ค.
filter๋ฅผ ๋จผ์ ํ ๋ค์ map์ ํด๋ ๋๋๋ฐ ๊ทธ ๋ฐ๋๋ก ํ๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋ฌ๋ฉด filter๋ก ๊ฑธ๋ฌ์ง ๋์์ ๋ํด์๋ ๋ถํ์ํ map ๋ฐ๋ณต์ ๋ ๊ฒ์ด๋ค.
์ด๊ฑธ ๋ค์ ์์๋ง ์กฐ์ ํด์ค๋

์กฐ๊ธ ๋ ๋๋ฑํ ์์ค๊น์ง ์ต์ ํ๊ฐ ๋๋ ๊ฒ ๊ฐ๋ค. ๋ฌผ๋ก ์๋ค๊ฐ๋ค ํ๊ธด ํ๋๋ฐ, iterator๊ฐ ๋น ๋ฅด๊ฒ ๋์ฌ ๋๋ ์๋ค.
์๋ฌดํผ ๋ฏธ๋ฌํ๊ธด ํ์ง๋ง Rust๋ map๊ณผ filter๋ก ๊ตฌ์ฑ๋ ๋ณตํฉ iteration์ ๊ฒฝ์ฐ์๋ ์ด๋์ ๋ for ๋ฃจํ์ ๋์ผํ ํํ๋ก ์ต์ ํ๋ฅผ ํด์ค๋ค. ๊ทธ๋์ for ๋ฒ์ ์ ์ฝ๋์ ์๋ฒฝํ๊ฒ ๋์ผํ ๋ฐ์ด๋๋ฆฌ๋ฅผ ๋ฐฉ์ถํ ๋๋ ๋ง๋ค.
์ด๋ฐ๊ฑธ Haskell์์๋ fusion์ด๋ผ๊ณ ๋ถ๋ฅด๋๋ผ.
์ฐธ์กฐ
https://doc.rust-lang.org/book/ch13-04-performance.html
https://ntietz.com/blog/rusts-iterators-optimize-footgun/