我们将尝试使用 Rust 来比较读取文件的各种不同方法。除了 wc -l
之外,我们将使用 criterion
对每个函数运行 10 次,然后取平均值。
以下基准测试的代码存放在 Benchmark code for Linux IO using Rust。
在以下代码中,BUFFER_SIZE 为 8192,NUM_BUFFERS 为 32。
原文: # Linux File IO using Rust](https://opdroid.org/rust-io.html)) by opdroid
读取方法 | 时间 (单位:秒) |
---|---|
Mmap with AVX512 | 2.61 |
Mmap with AVX2 | 2.64 |
io_uring with Vectored IO | 2.86 |
Vectored IO | 2.89 |
Mmap | 3.43 |
io_uring | 5.26 |
wc -l (baseline) | 8.01 |
Direct IO | 10.56 |
BufReader without appends | 15.94 |
BufReader with lines().count() | 33.50 |
一个有趣的观察是,AVX512 需要 2.61 秒,文件大小约为 22G,而 SSD 基准测试显示读取速度为 3.6 GB/s。这意味着文件应该在大约 6 秒内被读取完毕。但 AVX512 的实现实际上是以约 8.4 GB/s 的速度读取文件。
这是怎么回事呢?比磁盘的读取速度都快不少?不科学啊?
原来 Fedora 使用了 btrfs 文件系统,它默认启用了 zstd 压缩。实际的磁盘上大小可以使用 compsize
命令来查看。
|
|
感谢这些优秀的人
BufReader
的合理默认值,并编译为本机架构。 wc
数字中的一个明显错误。我在使用 wc
测量之前忘记了清空缓存。 不使用我们编写的代码作为基线总是一个好主意,这样比较客观。
wc -l
作为基线
|
|
在每个函数的末尾,我们使用以下命令重置文件缓存。我还没有弄清楚如何在 criterion 中使用 teardown 函数,以便这个时间不被计入总耗时。
|
|
BufReader
读取文件,并使用 reader.lines().count()
计算行数
|
|
在我的机器上,这需要大约 36.5 秒的时间。
在 count_newlines_standard
函数中,字符串拼接(String appends)可能是导致性能问题的原因。
BufReader
读取文件并避免字符串拼接
|
|
在我的机器上,这大约需要 15.94 秒。这比使用字符串拼接的版本快了一半以上。
当我们查看火焰图时,我们可以确认字符串拼接的操作已经不存在了。
|
|
在我的机器上,这大约需要 35.7 秒。
|
|
在我的机器上,这大约需要 8.3 秒。
|
|
这个方法在我的机器上大约耗时 2.64 秒。
|
|
这个方法在我的机器上大约需要 2.61 秒。
|
|
在我的机器上,这大约需要 7.7 秒。
io_uring
读取文件
|
|
在我的机器上,这大约需要 10.5 秒。
io_uring
读取文件
|
|
在我的机器上,这大约需要 7.6 秒。