James
James

Reputation: 753

Is creating a large Vec full of sequential u64 faster via loop and push() or via collect()?

I am looking for the most efficient way of doing this as I have to create a vector of about 600,000 u64 integers.

Here is my first attempt:

fn latest_ids(current_id: u64, latest_id: u64) -> Vec<u64> {
    let mut ids: Vec<u64> = vec![];
    let mut start = current_id;
    while !(start >= latest_id) {
        start += 1;
        ids.push(start);
    }
    ids
}

Second attempt:

fn latest_ids(current_id: u64, latest_id: u64) -> Vec<u64> {
    let ids: Vec<u64> = (current_id+1..latest_id).collect();
    ids
}

The second version is much shorter/cleaner, but I am not sure how efficient collect() is going to be? Or perhaps there is a better way?

Upvotes: 2

Views: 538

Answers (1)

frick
frick

Reputation: 166

If you're ever in doubt about performance in Rust, don't forget about benchmarks.

#![feature(test)]

extern crate test;

#[cfg(test)]
mod tests {
    use test::Bencher;

    const CURRENT_ID: u64 = 1;
    const LATEST_ID: u64 = 60000;

    #[bench]
    fn push(b: &mut Bencher) {
        b.iter(|| {
            let mut ids: Vec<u64> = vec![];
            let mut start = CURRENT_ID;

            while !(start >= LATEST_ID) {
                start += 1;
                ids.push(start);
            }
        });
    }

    #[bench]
    fn collect(b: &mut Bencher) {
        b.iter(|| {
            let _ids: Vec<u64> = (CURRENT_ID + 1..LATEST_ID).collect();
        });
    }
}

Running cargo bench,

running 2 tests
test tests::collect ... bench:      29,931 ns/iter (+/- 6,842)
test tests::push    ... bench:      85,701 ns/iter (+/- 18,096)

You can see that collect is actually faster than push (by a lot). I'm guessing this has to do with push sometimes having to clone the whole Vec and move it to a different location in memory (don't quote me on that though).

Upvotes: 1

Related Questions