3

The code below runs much slower when calling read_line(..) than lines() You can't run it in the playground but for me this prints the following

lines()     took Duration { secs: 0, nanos: 41660031 }
read_line() took Duration { secs: 2, nanos: 379397138 }

The implementation of Lines does pretty much what I wrote (but more!) why is there such a difference?

use std::net::{TcpListener, TcpStream};
use std::io::{BufRead, BufReader, Write};
use std::thread;

fn main() {

    let listener = TcpListener::bind("127.0.0.1:80")
        .expect("listen failed");
    thread::spawn(move || {
        for stream in listener.incoming() {
            let mut stream = stream.unwrap();
            thread::spawn(move || {
                for x in 1..1000 + 1 {
                    stream.write_all(format!("{}\n", x).as_bytes())
                        .expect("write failed");
                }
            });
        }
    });

    let start_a = std::time::Instant::now();
    {
        let stream_a = TcpStream::connect("127.0.0.1:80")
            .expect("connect_a failed");
        let br = BufReader::new(stream_a);
        for l in br.lines() {
            println!("{}", l.unwrap());
        }
    }
    let end_a = std::time::Instant::now();

    let start_b = std::time::Instant::now();
    {
        let stream_b = TcpStream::connect("127.0.0.1:80")
            .expect("connect_b failed");
        let mut br = BufReader::new(stream_b);
        let mut s = String::with_capacity(10);
        while br.read_line(&mut s).unwrap_or(0) > 0 {
            println!("{}", s);
        }
    }
    let end_b = std::time::Instant::now();

    let dur_a = end_a - start_a;
    let dur_b = end_b - start_b;

    println!("lines()     took {:?}", dur_a);
    println!("read_line() took {:?}", dur_b);

}

same code on the playground

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
dten
  • 2,364
  • 21
  • 28
  • 2
    **Did you test using the `--release` flag**? That's the #1 issue whenever someone says that Rust code isn't "fast enough". – Shepmaster Jul 20 '17 at 16:42

1 Answers1

13

Let's take a look at the output of your program:

1 
2 
...
999
1000
1

1
2

1
2
3

1
2
3
4

1
2
3
4
5

...

Ooops. It's just a simple bug in your code: you never clear() the string. Each read_line() call appends to your string. When I add a s.clear() in your while loop, the timings are more comparable:

lines()     took Duration { secs: 0, nanos: 7323617 }
read_line() took Duration { secs: 0, nanos: 2877078 }

In your buggy program, most of the time was probably wasted reallocating the string and printing it to the terminal.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305