Rust -> 23.2MiB/s
Python3 -> 28.6MiB/s
C -> 238MiB/s
Does anyone know why Rust's performance is in the same ballpark as Python3.
I thought it would be more closer to C.
Rust -> 23.2MiB/s
Python3 -> 28.6MiB/s
C -> 238MiB/s
Does anyone know why Rust's performance is in the same ballpark as Python3.
I thought it would be more closer to C.
In order to get similar performance as C, you probably need to take care of this lock yourself:
let mut lock = stdout().lock();
write!(lock, "hello world").unwrap();
(And also you need to make the buffering size for stdout match C’s.)Huh? Traditionally, stdio implementations have placed locks around all I/O[1] when introducing threads—thus functions such as fputc_unlocked to claw back at least some of the performance when the stock bulk functions don’t suffice—and the current ISO C standard even requires it (N3096 7.23.2p8):
> All functions that read, write, position, or query the position of a stream lock the stream before accessing it. They release the lock associated with the stream when the access is complete.
The Microsoft C runtime used to have a statically linked non-threaded version with no locks, but it no longer does. (I’ve always assumed that linking -lpthread as required on some Unices was also intended to override some of the -lc code with thread-safe versions, but I’m not sure; in any case this doesn’t play well with dynamic linking, and Glibc doesn’t do it that way.)
[1] e.g. see https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iofpu...
https://ismailmaj.github.io/tinkering-with-fizz-buzz-and-con...
Here's a C program counting, with a 1ms delay between lines. The second column is a duration since the previous read():
$ ./out | rtss
4.7ms 4.7ms | 1
4.7ms | 2
4.7ms | 3
4.7ms | 4
4.8ms exit status: 0
You can see they were all written in one go. When allocated a terminal, they come out line by line: $ rtss --pty ./out
0.8ms 0.8ms | 1
1.9ms 1.1ms | 2
3.0ms 1.1ms | 3
4.1ms 1.1ms | 4
4.3ms exit status: 0
Rust lacks this adaptive behaviour for output, and will always produce the second result, terminal or not.Technically it unconditionally wraps stdout in a LineWriter (https://doc.rust-lang.org/std/io/struct.LineWriter.html), which always flushes if it sees a write containing a newline. To maximise throughput you therefore want to batch writes of multiple lines together, for example by wrapping it in a BufWriter.