管道和重定向速度、“pv”和 UUOC

管道和重定向速度、“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/秒,这非常令人印象深刻,特别是与〜70MB我从/dev/urandom.

/dev/zero但是,嘿,对于我不需要的特殊情况cat!只是为了好玩,我删除了这本教科书乌鲁木齐大学:

$ < /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咎由自取吗?管道与重定向有很大不同吗?毕竟,两者都转到pvas stdin,对吗?什么可以解释这种巨大的差异呢?

答案1

杀手锏是使用了两个进程。

cat | pvcat读和写,pv读和写,两个进程都需要运行:

$ 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从管道复制数据,避免遍历内核拥有的内存。

相关内容