Closed
Description
I noticed today that using Vec::retain
is much slower than filtering and allocating a new Vector.
I realize the former is probably more memory efficient, but I still found it surprising that it would be that much slower (or really slower at all).
When testing with this code:
#![feature(test)]
extern crate test;
fn main() {
let xs: Vec<i32> = (0..1000).collect();
assert_eq!(even_with_retain(xs.clone()), even_with_filter(xs.clone()));
}
pub fn even_with_retain(mut xs: Vec<i32>) -> Vec<i32> {
xs.retain(|x| x & 1 == 0);
xs
}
pub fn even_with_filter(xs: Vec<i32>) -> Vec<i32> {
xs.into_iter().filter(|x| x & 1 == 0).collect()
}
#[bench]
fn bench_retain(b: &mut test::Bencher) {
let xs: Vec<i32> = (0..1000).collect();
b.iter(|| assert_eq!(even_with_retain(test::black_box(xs.clone())).len(), 500));
}
#[bench]
fn bench_filter_collect(b: &mut test::Bencher) {
let xs: Vec<i32> = (0..1000).collect();
b.iter(|| assert_eq!(even_with_filter(test::black_box(xs.clone())).len(), 500));
}
on 1.59.0-nightly (48a5999 2021-12-01), I get these benchmark results:
test bench_filter_collect ... bench: 383 ns/iter (+/- 4)
test bench_retain ... bench: 1,891 ns/iter (+/- 17)
on a Ryzen 5900X running Linux. Testing on a different machine (Xeon E3-1271 v3), I get similar numbers:
test bench_filter_collect ... bench: 498 ns/iter (+/- 29)
test bench_retain ... bench: 1,800 ns/iter (+/- 44)
Vec::retain
seemed like the obvious choice to me, so it being slower is either a bug or should be documented somewhere.
Metadata
Metadata
Assignees
Labels
Area: Code generationArea: `std::collections`Area: IteratorsCategory: This is a bug.Issue: Problems and improvements with respect to performance of generated code.Relevant to the compiler team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.