tmpfs 访问单个文件比访问多个文件慢

tmpfs 访问单个文件比访问多个文件慢

读取不同的(1.6 GB)块相同的文件存储tmpfs在大约 20 个线程时最大速度为 2.5GB/s:

在此输入图像描述

但如果相同的块被分成不同的文件,tmpfs我可以获得 22GB/s:

在此输入图像描述

是什么造成了这个瓶颈?有没有一种方法可以让我tmpfs在单个文件上的工作速度与在多个文件上的工作速度一样快?

重现

看写比看容易得多,但问题和速度差异是相似的:

$ cd /mnt/tmpfs
$ cores=$(seq 64)
$ # -u disables GNU Parallel's on-disk buffer
$ time parallel -n0 -u  'yes $(seq 1000) | head -c 1600M' ::: $cores > 100g

real    3m54.286s
user    1m10.592s
sys     246m42.804s

$ time parallel 'yes $(seq 1000) | head -c 1600M > {#}' ::: $cores

real    0m26.308s
user    1m21.283s
sys     24m45.152s

您需要安装 64 个内核和 200 GB RAM(无交换)才能tmpfs执行此操作,但您可能可以使用较小的硬件重现效果。

如果您没有 GNU Parallel,您可以通过以下方式获得类似的数字:

time (
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
wait
) > 100g

time (
yes $(seq 1000) | head -c 1600M > 1 &
yes $(seq 1000) | head -c 1600M > 2 &
yes $(seq 1000) | head -c 1600M > 3 &
yes $(seq 1000) | head -c 1600M > 4 &
yes $(seq 1000) | head -c 1600M > 5 &
yes $(seq 1000) | head -c 1600M > 6 &
yes $(seq 1000) | head -c 1600M > 7 &
yes $(seq 1000) | head -c 1600M > 8 &
yes $(seq 1000) | head -c 1600M > 9 &
yes $(seq 1000) | head -c 1600M > 10 &
yes $(seq 1000) | head -c 1600M > 11 &
yes $(seq 1000) | head -c 1600M > 12 &
yes $(seq 1000) | head -c 1600M > 13 &
yes $(seq 1000) | head -c 1600M > 14 &
yes $(seq 1000) | head -c 1600M > 15 &
yes $(seq 1000) | head -c 1600M > 16 &
yes $(seq 1000) | head -c 1600M > 17 &
yes $(seq 1000) | head -c 1600M > 18 &
yes $(seq 1000) | head -c 1600M > 19 &
yes $(seq 1000) | head -c 1600M > 20 &
yes $(seq 1000) | head -c 1600M > 21 &
yes $(seq 1000) | head -c 1600M > 22 &
yes $(seq 1000) | head -c 1600M > 23 &
yes $(seq 1000) | head -c 1600M > 24 &
yes $(seq 1000) | head -c 1600M > 25 &
yes $(seq 1000) | head -c 1600M > 26 &
yes $(seq 1000) | head -c 1600M > 27 &
yes $(seq 1000) | head -c 1600M > 28 &
yes $(seq 1000) | head -c 1600M > 29 &
yes $(seq 1000) | head -c 1600M > 30 &
yes $(seq 1000) | head -c 1600M > 31 &
yes $(seq 1000) | head -c 1600M > 32 &
yes $(seq 1000) | head -c 1600M > 33 &
yes $(seq 1000) | head -c 1600M > 34 &
yes $(seq 1000) | head -c 1600M > 35 &
yes $(seq 1000) | head -c 1600M > 36 &
yes $(seq 1000) | head -c 1600M > 37 &
yes $(seq 1000) | head -c 1600M > 38 &
yes $(seq 1000) | head -c 1600M > 39 &
yes $(seq 1000) | head -c 1600M > 40 &
yes $(seq 1000) | head -c 1600M > 41 &
yes $(seq 1000) | head -c 1600M > 42 &
yes $(seq 1000) | head -c 1600M > 43 &
yes $(seq 1000) | head -c 1600M > 44 &
yes $(seq 1000) | head -c 1600M > 45 &
yes $(seq 1000) | head -c 1600M > 46 &
yes $(seq 1000) | head -c 1600M > 47 &
yes $(seq 1000) | head -c 1600M > 48 &
yes $(seq 1000) | head -c 1600M > 49 &
yes $(seq 1000) | head -c 1600M > 50 &
yes $(seq 1000) | head -c 1600M > 51 &
yes $(seq 1000) | head -c 1600M > 52 &
yes $(seq 1000) | head -c 1600M > 53 &
yes $(seq 1000) | head -c 1600M > 54 &
yes $(seq 1000) | head -c 1600M > 55 &
yes $(seq 1000) | head -c 1600M > 56 &
yes $(seq 1000) | head -c 1600M > 57 &
yes $(seq 1000) | head -c 1600M > 58 &
yes $(seq 1000) | head -c 1600M > 59 &
yes $(seq 1000) | head -c 1600M > 60 &
yes $(seq 1000) | head -c 1600M > 61 &
yes $(seq 1000) | head -c 1600M > 62 &
yes $(seq 1000) | head -c 1600M > 63 &
yes $(seq 1000) | head -c 1600M > 64 &
wait
)

tmpfsUbuntu 20.04 中默认为:

$ uname -a
Linux r815 5.4.0-66-generic #74-Ubuntu SMP Wed Jan 27 22:54:38 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
$ mount
tmpfs on /mnt/tmpfs type tmpfs (rw,noatime)

我不确定它是否对我们有帮助,但似乎类似的情况也适用于 HDD 块设备:

# Read the full disk into cache
sudo pv /dev/sde >/dev/null
# Read the full disk again from cache
time sudo cat /dev/sde >/dev/null

real    1m20.100s
user    0m0.739s
sys     1m19.351s

# Read the full disk again from cache 64 times in parallel
seq 64 | time sudo parallel -N0 'cat /dev/sde >/dev/null'

297.64user 39359.17system 12:44.60elapsed 5186%CPU (0avgtext+0avgdata 19752maxresident)k
0inputs+8outputs (0major+117384minor)pagefaults 0swaps

# Read the full disk again from cache as 64 parts in parallel
time sudo parallel -a /dev/sde --pipepart --block -1 -u 'cat >/dev/null'
real    1m5.796s
user    0m13.331s
sys     67m34.396s

相关内容