Pipe管道和重定向速度,
管道和重定向速度,pv
和 UUOC
我正在測試不同的方法來產生隨機垃圾,並通過管道輸出來比較它們的速度
pv
,如下所示:$ cmd | pv -s "$size" -S > /dev/null
我還想要一個“基準參考”,所以我測量了最快的“生成器”,
cat
具有最快的源,/dev/zero
:$ cat /dev/zero | pv -s 100G -S > /dev/null 100GiB 0:00:33 [2,98GiB/s] [=============================>] 100%
3GB/s **,**這非常令人印象深刻,特別是與我從
/dev/urandom
.但是,嘿,對於
/dev/zero
我不需要的特殊情況cat
!只是為了好玩,我刪除了這本教科書UUOC:$ < /dev/zero pv -s 100G -S > /dev/null 100GiB 0:00:10 [9,98GiB/s] [=============================>] 100%
什麼???幾乎10GB/秒? 怎樣才能將
cat
管道的拆除速度提高三倍以上?如果使用較慢的源,例如/dev/urandom
差異可以忽略不計。是pv
在做一些巫毒魔法嗎?所以我測試了:$ dd if=/dev/zero iflag=count_bytes count=200G of=/dev/null status=progress 205392969728 bytes (205 GB, 191 GiB) copied, 16 s, 12,8 GB/s
12,8 GB/秒!與 相同的球場
pv
,比使用管道快 4 倍。是
cat
罪魁禍首嗎?管道與重定向有很大不同嗎?畢竟,兩者都去pv
asstdin
,對吧?什麼可以解釋這種巨大的差異?
殺手鐧是使用兩個程序。
With
cat | pv
,cat
reads and writes, andpv
reads and writes, 兩個程序都需要執行:$ perf stat sh -c 'cat /dev/zero | pv -s 100G -S > /dev/null' 100GiB 0:00:26 [3.72GiB/s] [====================================================================================>] 100% Performance counter stats for 'sh -c cat /dev/zero | pv -s 100G -S > /dev/null': 34,048.63 msec task-clock # 1.267 CPUs utilized 1,676,706 context-switches # 0.049 M/sec 3,678 cpu-migrations # 0.108 K/sec 304 page-faults # 0.009 K/sec 119,270,941,758 cycles # 3.503 GHz (74.89%) 137,822,862,590 instructions # 1.16 insn per cycle (74.94%) 32,379,369,104 branches # 950.974 M/sec (75.14%) 216,658,446 branch-misses # 0.67% of all branches (75.04%) 26.865741948 seconds time elapsed 1.257950000 seconds user 38.893870000 seconds sys
pv
只需要讀取和pv
寫入,不需要上下文切換(或幾乎不需要):$ perf stat sh -c '< /dev/zero pv -s 100G -S > /dev/null' 100GiB 0:00:07 [13.3GiB/s] [====================================================================================>] 100% Performance counter stats for 'sh -c < /dev/zero pv -s 100G -S > /dev/null': 7,501.68 msec task-clock # 1.000 CPUs utilized 37 context-switches # 0.005 K/sec 0 cpu-migrations # 0.000 K/sec 198 page-faults # 0.026 K/sec 27,916,420,023 cycles # 3.721 GHz (75.00%) 62,787,377,126 instructions # 2.25 insn per cycle (74.99%) 15,361,951,954 branches # 2047.801 M/sec (75.03%) 51,741,595 branch-misses # 0.34% of all branches (74.98%) 7.505304560 seconds time elapsed 1.768600000 seconds user 5.733786000 seconds sys
有一些並行性(“使用了 1.267 個 CPU”),但這並不能彌補上下文切換數量上的巨大差異。
考慮到數據路徑,情況可能會更糟——在第一種情況下,數據似乎
/dev/zero
從cat
核心pv
(/dev/null
第二個,數據從核心流向pv
,返回核心。但在第一種情況下,pv
用於splice
從管道複製數據,避免通過核心擁有的記憶體。