このシングルライナーをより速くする方法はありますか?

このシングルライナーをより速くする方法はありますか?

コンテキスト

私はそれぞれ約300Kの表形式で日付が指定された何千ものzipファイルを含むディレクトリを持っていますYYYYMMDD_hhmmss.zip。各zipファイルには約400個のxmlファイルがあり、各ファイルのサイズは約3Kです。

質問

zipファイルの日付範囲内で特定の文字列を検索して見つけることができるはずです。

現在(通常ですが)ソリューション

私は次の行を持っています

find /home/mydir/ -type f | sort | \
awk "/xml_20140207_000016.zip/,/xml_20140207_235938.zip/" | \
xargs -n 1 -P 10 zipgrep "my search string"

ポイントは

  1. 私の1000ファイルディレクトリのすべてのファイルを一覧表示する
  2. このファイルリストの並べ替え
  3. 指定された日付に基づいてファイル範囲を検索します(このawkコマンドは、最初の一致文字列の後の行と2番目の一致文字列の前の行のみを印刷します)
  4. 単一のファイルに対応する各結果行を次に渡します。zipgrep

質問

24コアシステムに10個のプロセスがあっても、このコードの1行は非常に遅く実行されます。zipgrep命令のために遅いと思いますが、改善方法を知るほどスマートではありません。これを行うべきかどうかはわかりませんが、同僚がこのスクリプトよりも速く実行するJavaツールを作成したので、少し困惑しています。できればこれを裏返したいです。それでは、この場合、このコマンドをより速くする方法を知っている人はいますか?それともどの部分を改善しますか?

ベストアンサー1

簡単に改善できる区間が一つありますが、最も遅い区間ではありません。

find /home/mydir/ -type f | sort | \
awk "/xml_20140207_000016.zip/,/xml_20140207_235938.zip/"

これは最初にすべてのファイルをリストし、次にファイル名をソートし、興味のあるファイルを抽出するため、少し無駄です。findソートを開始する前に、コマンドを完了する必要があります。

まず、関心のあるファイルのみを一覧表示するか、少なくとも可能な最小の親セットを一覧表示する方が高速です。 names に対してよりきめ細かいフィルタが必要な場合は、findawk にパイプするがソートしないでください。 awkおよび他の行ごとのフィルタは1行ずつ処理できますが、ソートには完全な入力が必要です。

find /home/mydir/ -name 'xml_20140207_??????.zip' -type f | \
awk 'match($0, /_[0-9]*.zip$/) &&
     (time = substr($0, RSTART+1, RLENGTH-5)) &&
     time >= 16 && time <= 235938' |
xargs -n 1 -P 10 zipgrep "my search string"

最も明らかに、次善策の部分はzipgrepです。シェルプログラミングの制限によりパフォーマンスを向上させる簡単な方法はありません。 zipgrepスクリプトは、アーカイブのファイル名をリストし、grep各ファイルの内容を1つずつ呼び出す方法で機能します。これは、zipアーカイブのすべてのファイルが引き続き解析されることを意味します。 Javaプログラム(またはPerl、Python、Rubyなど)はファイルを一度だけ処理してこれを防ぐことができます。

シェルプログラミングに固執するには、zipgrepを使用する代わりに各zipをマウントしてみることができます。

… | xargs -n1 -P2 sh -c '
    mkdir "mnt$$-$1";
    fuse-zip "$1" "mnt$$-$1";
    grep -R "$0" "mnt$$-$1"
    fusermount -u "mnt$$-$1"
' "my search string"

並列処理はあまり役に立ちません。ほとんどの設定では、制限要因はCPU時間ではなくディスクI / O帯域幅です。

ベンチマークしたことはありませんが、最大の改善分野は言語でzipgrepのより強力な実装を使用することだと思います。

おすすめ記事