为什么 read_line(..) 比 lines() 慢得多?

3
以下代码在调用 read_line(..) 时运行速度要慢得多,而不是 lines()。 您无法在playground中运行它,但对我来说,它会打印以下内容。
lines()     took Duration { secs: 0, nanos: 41660031 }
read_line() took Duration { secs: 2, nanos: 379397138 }

Lines的实现方式基本上就是我所写的(但更多!)为什么会有这样的差异?

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);

}

同样的代码在游乐场上


2
你是否使用了 --release 标志进行测试?每当有人说 Rust 代码不够快时,这通常是最常见的问题。 - Shepmaster
1个回答

13

让我们来看一下您程序的输出:

1 
2 
...
999
1000
1

1
2

1
2
3

1
2
3
4

1
2
3
4
5

...

哎呀,你的代码中只是一个简单的错误:你从来没有调用clear()方法清空字符串。每次调用read_line()方法都会将其附加到字符串末尾。当我在while循环中加入一个s.clear()方法后,时间就更加可比了:

lines()     took Duration { secs: 0, nanos: 7323617 }
read_line() took Duration { secs: 0, nanos: 2877078 }
在您的错误程序中,大部分时间可能用于重新分配字符串和将其打印到终端上。

1
天才!非常感谢。 - dten
15年的编程经验,但这个问题也困扰了我。感觉在Rust中应该很难犯这种错误,但实际上并非如此。 - Petrus Theron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接