Open
Description
While working on a SO question.
We was wondering if chain()
would produce an acceptable speed, after some digging and benchmark, we come to the conclusion that collect()
is slow because it use while let
. Unfortunately, this make collect very slow, I don't really understand why but that a fact.
But we saw that for_each()
(probably thank to fold()
) implementation of chain()
don't have this problem and produce something a lot faster.
#![feature(test)]
extern crate test;
use either::Either; // 1.5.2
use std::iter;
#[derive(Debug, Default)]
pub struct Data<X, Y> {
head: Option<Y>,
pairs: Vec<(X, Y)>,
tail: Option<X>,
}
impl<X, Y> Data<X, Y> {
pub fn iter(&self) -> impl Iterator<Item = Either<&X, &Y>> {
let head = self.head.iter().map(Either::Right);
let pairs = self.pairs.iter().flat_map(|(a, b)| {
let a = iter::once(Either::Left(a));
let b = iter::once(Either::Right(b));
a.chain(b)
});
let tail = self.tail.iter().map(Either::Left);
head.chain(pairs).chain(tail)
}
}
#[derive(Debug)]
struct AData(usize);
#[derive(Debug)]
struct BData(usize);
#[cfg(test)]
mod tests {
use crate::{AData, BData, Data};
use test::Bencher; // 1.5.2
#[bench]
fn test_for_each(b: &mut Bencher) {
b.iter(|| {
let data = Data {
head: Some(BData(84)),
pairs: std::iter::repeat_with(|| (AData(42), BData(84)))
.take(20998)
.collect(),
tail: Some(AData(42)),
};
let mut data_bis = Vec::with_capacity(21000);
data.iter().for_each(|x| data_bis.push(x));
});
}
#[bench]
fn test_collect(b: &mut Bencher) {
b.iter(|| {
let data = Data {
head: Some(BData(84)),
pairs: std::iter::repeat_with(|| (AData(42), BData(84)))
.take(20998)
.collect(),
tail: Some(AData(42)),
};
let _: Vec<_> = data.iter().collect();
});
}
}
test tests::test_collect ... bench: 1,682,529 ns/iter (+/- 2,157,023)
test tests::test_for_each ... bench: 609,031 ns/iter (+/- 750,944)
So, should we change implementation of collect to use for_each()
? Note that a for loop doesn't solve the problem. For this to be optimized we need to use for_each()
.
Metadata
Metadata
Assignees
Labels
Area: IteratorsCategory: An issue proposing an enhancement or a PR with one.Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.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 API team, which will review and decide on the PR/issue.