Skip to content

str::splitn(N, ' ') is slower than it ought to be #82471

Open
@jeffsmith82

Description

I wrote a small benchmark and was surprised at how much slower it was using str::splitn rather than using bytes directly.

splitn
Time elapsed in parse_response() is: 2.290853462s

as bytes
Time elapsed in parse_response() is: 661.947666ms

Is it possible to do something similar to #46693 where if splitting on a single byte.

https://users.rust-lang.org/t/performance-comparison/56041/2

use std::time::{Duration, Instant};
fn main() {
    let response = String::from("HTTP/1.1 418 I'm a teapot\r\n");
    let mut res: (&str, &str, &str) = ("", "", "");
    let start = Instant::now();
    for _ in 0..100_000_000 {
        res = match parse_http(&response) {
            Ok(data) => data,
            Err(_) => {
                continue;
            }
        };
    }
    let duration = start.elapsed();

    println!("version:{}\ncode:{}\ndescription:{}\n", res.0, res.1, res.2);
    println!("Time elapsed in parse_response() is: {:?}", duration);
    
    let start2 = Instant::now();
    for _ in 0..100_000_000 {
        res = match parse_http2(&response) {
            Ok(data) => data,
            Err(_) => {
                continue;
            }
        };
    }
    let duration2 = start2.elapsed();

    println!("version:{}\ncode:{}\ndescription:{}\n", res.0, res.1, res.2);
    println!("Time elapsed in parse_response() is: {:?}", duration2);
}

fn parse_http(s: &str) -> Result<(&str, &str, &str), &str> {
    let mut parts = s.splitn(3, ' ');
    let version = parts.next().ok_or("No Version")?;
    let code = parts.next().ok_or("No status code")?;
    let description = parts.next().ok_or("No description")?;
    Ok((version, code, description))
}

fn parse_http2(s: &str) -> Result<(&str, &str, &str), &str> {
    let mut bytes = s.as_bytes().iter();
    let i = bytes.position(|b| *b == b' ').ok_or("No Version")?;
    let j = bytes.position(|b| *b == b' ').ok_or("No status code")? + i + 1;

    let version = &s[..i];
    let code = &s[(i + 1)..j];
    let description = &s[(j + 1)..];
    Ok((version, code, description))
}

Metadata

Assignees

No one assigned

    Labels

    A-strArea: str and StringC-enhancementCategory: An issue proposing an enhancement or a PR with one.I-slowIssue: Problems and improvements with respect to performance of generated code.T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions