「cat」を「無駄に」使用すると、パフォーマンスが向上する可能性があります。なぜ?

「cat」を「無駄に」使用すると、パフォーマンスが向上する可能性があります。なぜ?

ファイル1..64はそれぞれ160MBで、RAMディスクに保存されます。

によって作成された:

seq 120 | parallel -k 'seq {}0000000 {}9999999 | fmt -30' | head -c 10G > 10G
parallel --pipepart --block -1 -a 10G -j 64 'cat > {#}'

nocat:

#!/bin/bash

export LC_ALL=C
sort -m \
     <(sort -m  \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 1; sort ) < 1) \
                                        <((rm 2; sort ) < 2) ) \
                                 <(sort -m  \
                                        <((rm 3; sort ) < 3) \
                                        <((rm 4; sort ) < 4) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 5; sort ) < 5) \
                                        <((rm 6; sort ) < 6) ) \
                                 <(sort -m  \
                                        <((rm 7; sort ) < 7) \
                                        <((rm 8; sort ) < 8) ) ) ) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 9; sort ) < 9) \
                                        <((rm 10; sort ) < 10) ) \
                                 <(sort -m  \
                                        <((rm 11; sort ) < 11) \
                                        <((rm 12; sort ) < 12) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 13; sort ) < 13) \
                                        <((rm 14; sort ) < 14) ) \
                                 <(sort -m  \
                                        <((rm 15; sort ) < 15) \
                                        <((rm 16; sort ) < 16) ) ) ) ) \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 17; sort ) < 17) \
                                        <((rm 18; sort ) < 18) ) \
                                 <(sort -m  \
                                        <((rm 19; sort ) < 19) \
                                        <((rm 20; sort ) < 20) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 21; sort ) < 21) \
                                        <((rm 22; sort ) < 22) ) \
                                 <(sort -m  \
                                        <((rm 23; sort ) < 23) \
                                        <((rm 24; sort ) < 24) ) ) ) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 25; sort ) < 25) \
                                        <((rm 26; sort ) < 26) ) \
                                 <(sort -m  \
                                        <((rm 27; sort ) < 27) \
                                        <((rm 28; sort ) < 28) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 29; sort ) < 29) \
                                        <((rm 30; sort ) < 30) ) \
                                 <(sort -m  \
                                        <((rm 31; sort ) < 31) \
                                        <((rm 32; sort ) < 32) ) ) ) ) ) \
     <(sort -m  \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 33; sort ) < 33) \
                                        <((rm 34; sort ) < 34) ) \
                                 <(sort -m  \
                                        <((rm 35; sort ) < 35) \
                                        <((rm 36; sort ) < 36) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 37; sort ) < 37) \
                                        <((rm 38; sort ) < 38) ) \
                                 <(sort -m  \
                                        <((rm 39; sort ) < 39) \
                                        <((rm 40; sort ) < 40) ) ) ) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 41; sort ) < 41) \
                                        <((rm 42; sort ) < 42) ) \
                                 <(sort -m  \
                                        <((rm 43; sort ) < 43) \
                                        <((rm 44; sort ) < 44) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 45; sort ) < 45) \
                                        <((rm 46; sort ) < 46) ) \
                                 <(sort -m  \
                                        <((rm 47; sort ) < 47) \
                                        <((rm 48; sort ) < 48) ) ) ) ) \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 49; sort ) < 49) \
                                        <((rm 50; sort ) < 50) ) \
                                 <(sort -m  \
                                        <((rm 51; sort ) < 51) \
                                        <((rm 52; sort ) < 52) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 53; sort ) < 53) \
                                        <((rm 54; sort ) < 54) ) \
                                 <(sort -m  \
                                        <((rm 55; sort ) < 55) \
                                        <((rm 56; sort ) < 56) ) ) ) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 57; sort ) < 57) \
                                        <((rm 58; sort ) < 58) ) \
                                 <(sort -m  \
                                        <((rm 59; sort ) < 59) \
                                        <((rm 60; sort ) < 60) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 61; sort ) < 61) \
                                        <((rm 62; sort ) < 62) ) \
                                 <(sort -m  \
                                        <((rm 63; sort ) < 63) \
                                        <((rm 64; sort ) < 64) ) ) ) ) ) |
    md5sum

withcat:

#!/bin/bash

export LC_ALL=C
sort -m \
     <(sort -m  \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 1; sort ) < 1) \
                                        <((rm 2; sort ) < 2) | cat) \
                                 <(sort -m  \
                                        <((rm 3; sort ) < 3) \
                                        <((rm 4; sort ) < 4) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 5; sort ) < 5) \
                                        <((rm 6; sort ) < 6) | cat) \
                                 <(sort -m  \
                                        <((rm 7; sort ) < 7) \
                                        <((rm 8; sort ) < 8) | cat) | cat) | cat) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 9; sort ) < 9) \
                                        <((rm 10; sort ) < 10) | cat) \
                                 <(sort -m  \
                                        <((rm 11; sort ) < 11) \
                                        <((rm 12; sort ) < 12) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 13; sort ) < 13) \
                                        <((rm 14; sort ) < 14) | cat) \
                                 <(sort -m  \
                                        <((rm 15; sort ) < 15) \
                                        <((rm 16; sort ) < 16) | cat) | cat) | cat) | cat) \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 17; sort ) < 17) \
                                        <((rm 18; sort ) < 18) | cat) \
                                 <(sort -m  \
                                        <((rm 19; sort ) < 19) \
                                        <((rm 20; sort ) < 20) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 21; sort ) < 21) \
                                        <((rm 22; sort ) < 22) | cat) \
                                 <(sort -m  \
                                        <((rm 23; sort ) < 23) \
                                        <((rm 24; sort ) < 24) | cat) | cat) | cat) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 25; sort ) < 25) \
                                        <((rm 26; sort ) < 26) | cat) \
                                 <(sort -m  \
                                        <((rm 27; sort ) < 27) \
                                        <((rm 28; sort ) < 28) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 29; sort ) < 29) \
                                        <((rm 30; sort ) < 30) | cat) \
                                 <(sort -m  \
                                        <((rm 31; sort ) < 31) \
                                        <((rm 32; sort ) < 32) | cat) | cat) | cat) | cat) | cat) \
     <(sort -m  \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 33; sort ) < 33) \
                                        <((rm 34; sort ) < 34) | cat) \
                                 <(sort -m  \
                                        <((rm 35; sort ) < 35) \
                                        <((rm 36; sort ) < 36) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 37; sort ) < 37) \
                                        <((rm 38; sort ) < 38) | cat) \
                                 <(sort -m  \
                                        <((rm 39; sort ) < 39) \
                                        <((rm 40; sort ) < 40) | cat) | cat) | cat) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 41; sort ) < 41) \
                                        <((rm 42; sort ) < 42) | cat) \
                                 <(sort -m  \
                                        <((rm 43; sort ) < 43) \
                                        <((rm 44; sort ) < 44) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 45; sort ) < 45) \
                                        <((rm 46; sort ) < 46) | cat) \
                                 <(sort -m  \
                                        <((rm 47; sort ) < 47) \
                                        <((rm 48; sort ) < 48) | cat) | cat) | cat) | cat) \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 49; sort ) < 49) \
                                        <((rm 50; sort ) < 50) | cat) \
                                 <(sort -m  \
                                        <((rm 51; sort ) < 51) \
                                        <((rm 52; sort ) < 52) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 53; sort ) < 53) \
                                        <((rm 54; sort ) < 54) | cat) \
                                 <(sort -m  \
                                        <((rm 55; sort ) < 55) \
                                        <((rm 56; sort ) < 56) | cat) | cat) | cat) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 57; sort ) < 57) \
                                        <((rm 58; sort ) < 58) | cat) \
                                 <(sort -m  \
                                        <((rm 59; sort ) < 59) \
                                        <((rm 60; sort ) < 60) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 61; sort ) < 61) \
                                        <((rm 62; sort ) < 62) | cat) \
                                 <(sort -m  \
                                        <((rm 63; sort ) < 63) \
                                        <((rm 64; sort ) < 64) | cat) | cat) | cat) | cat) | cat) | cat |
    md5sum

唯一の違いは、withcatすべてがsort -mにパイプされていることですcat

「猫の役に立たない利用」 - 人々はあなたをwithcatよりゆっくりと信じさせますnocat。しかし、その逆は本当です。

$ time bash nocat
c933d81faea7b8dec8eb64ca0b044d74  -

real    3m40.854s
user    2m48.687s
sys     0m49.135s
$ time bash withcat
c933d81faea7b8dec8eb64ca0b044d74  -

real    2m21.812s
user    2m16.651s
sys     1m36.135s

このテストは64コアシステムで実行され、他の操作は実行されません。すべてがRAMにあります(したがってディスクが遅くなるわけではありません)。各テストは3回実行され、最良の時間は上に示されています。 3つのテストすべてが最高の時間から5秒以内に完了しました(それは偶然ではありませんでした)。

出力をパイプする方が速いのはなぜですかcat

編集する

グループ入力がcat大きくなるのでしょうか?そして/またはsort各ラインの出力をフラッシュしますか?

これをテストするために、次のことを試しました。

$ strace -ff sort -m <(sort 1) <(sort 2) 2>fromsort | cat >/dev/null
$ strace -ff sort -m <(sort 1 | cat ) <(sort 2 | cat) 2>fromcat | cat >/dev/null

cat大きなチャンクに分割すると、よりread大きなチャンクが返されると予想されます。しかし、そうではありません:

$ grep -E 'read|write' fromsort |field 1,5|sort | uniq -c 
      1 openat(AT_FDCWD,        3
      8 pread64(3,      =
      1 read(3, 3771
  40989 read(3, 4096
      2 read(3, 832
      1 read(3, unknown
      1 read(4, 0
      1 read(4, 2241
  40959 read(4, 4096
      1 write(1,        1916
  81949 write(1,        4096
$ grep -E 'read|write' fromcat |field 1,5|sort | uniq -c 
      1 openat(AT_FDCWD,        3
      8 pread64(3,      =
      1 read(3, 3771
  40989 read(3, 4096
      2 read(3, 832
      1 read(3, unknown
      1 read(4, 2241
  40959 read(4, 4096
      1 read(4, unknown
      1 write(1,        1916
  81949 write(1,        4096

どちらの場合も、read合計はwrite4Kです。

(ところで、sort するパイプではなくファイルから読み込む場合(より多く)、大きなチャンクを読みますが、ここではそうではありません。

編集2

上記の目的は、追加がcat必ずしも役に立たないわけではないことを示し、これが本当である理由を見つけることです。

目標はデータをソートすることではありません。

しかし目標なら以前はsortデータを並べ替えるには、組み込みデータを使用するとどうなりますか--parallel

64コアマシンでデフォルトで使用されているsortようです。 CPUの最大800%を使用していることを示しています。 64個のコアを使用するように強制できます。--parallel 8top--parallel 64

$ time sort {1..64} | md5sum
real    9m4.005s
user    29m56.454s
sys     5m49.560s

$ time sort --parallel 64 {1..64} | md5sum
real    6m50.332s
user    35m55.040s
sys     11m37.609s

したがって、GNUソートは--parallel上記のソートよりもはるかに遅くなります。これで上記のコンテンツを使用できますparsorthttp://git.savannah.gnu.org/cgit/parallel.git/tree/src/parsort

答え1

これは決して「猫の無駄な行動」ではない。

some_command | cat | some_command

これは伝統的な意味では「猫の目の前の路地」ではなく、通常はエンクロージャの無知から発生します。代わりに猫のダイナミズムを持って何かをしようとする意図的な試みのように見えます。この場合はキャッシュだと思います。


私の2番目の考え

読み取りと書き込みのサイズに違いがなくても、検出できないものが機能する可能性があります。

まず(非常に重要):ソートされていない配列よりもソートされた配列を処理する方が速いのはなぜですか?。 CPUがこのタスクを処理する順序を変更すると、タイミングが変わる可能性があります。中断(および他のプロセスに切り替える)なしでcat各実行時間を長くすることに成功すると、sortこれはCPUの分岐予測に大きな影響を与え、時間が長くなったり短くなったりする可能性があります。

次に、読み取り数とサイズが影響を受けない場合でも、ジョブを一時停止(ブロック)する必要がある回数は異なる場合があります。これはそれ自体でオーバーヘッドを増減することができます。したがって、読み出しと書き込みのサイズが同じであっても、(キャッシュ)階層は、1時間当たりの読み書きcat数を減らすことができる。read()write()

Catはソートを長く待つことで、中断することなくより多くの作業を実行し、各プロセスがブロックされる回数を減らすことができます。これは検出するのが難しいでしょう。


私の最初の考え

私の期待は、2つのバージョンを独自のスクリプトに配置し、strace -fそれぞれで実行すると、catを使用した例では、読み込みまたは書き込み呼び出しが少なくなることです。少なくともcatsort実際には、私はそれがread()十分に大きなブロックにありますが、write()単一の行にしかないことを望みます。これは、それ自体が配管されるように設計されていないことを意味します。

ロックタックが指摘したように、彼の答え、catは128KBチャンクで読みます(ねえ)しかし、パイプは通常64KBだけバッファリングします。私の考えが正しい場合は、キャットがread()完了するのを待っている間、停止せずに書き込むことsortができる大きな(128 + 64KB)バッファを書き込み操作に提供します。回復すると、次の書き込みに渡すcatデータが多くなります(sort単一の書き込みで送信されたものよりもはるかに多い)sort。だから次の人はsort止まることなくその内容をたくさん読むことができます。

私も疑う次へ追加最も近いファイル階層は、catパフォーマンスにほとんどまたはまったく影響しません。これらのファイルはすでにRAMディスクにキャッシュされています。ただし、呼び出し間のレイヤーはsortバッファーとして機能するため、その数を減らす必要があります。これは実際に「catの役に立たない使用」、つまりcatを使用してファイルを読み取る状況です。これは次の形式です。

cat some_file | some_command

興味深い実験

パイプのバッファサイズを増やして同じ効果が得られるかどうかを知りたいです。正しいプログラミング言語(シェルではない)を使用して同じパイプを設定する場合。たとえば、Cでは、、、を使用してパイプを作成し、各パイプを最初に呼び出してバッファサイズを増やすことができます(参照pipe()dup2()fork()exec()ioctl()パイプ容量)

答え2

私の考えでは、catを使用すると、各コマンドのスループットが制限され、コマンドが並列に高速で実行されるようです。

catデータの読み取り128KBチャンク。あなたのテストを再現することができないので、あなたの使い方を変えて、私が正しいかどうかを証明catできますか?dd

dd status=none bs=128K同じ効果があるはずですcat。チャンクサイズを増減することで結果を比較してみてください。

関連情報