フォルダー内の一部のファイルの移動に、フォルダー全体の移動よりも時間がかかるのはなぜですか?


21

ubuntuクラウドサーバーには数百万の画像があります。mvコマンドを使用して1200万枚の画像を含む完全なフォルダを移動すると、ほぼ瞬時に移動します。ただし、mv(フォルダではなく)画像のみの場合は、時間がかかります。すべての画像をフォルダと同じ速さで移動する方法はありますか?

これは何が起こっているかです:

  1. srcフォルダーには1200万の画像があり、これを使用してdstフォルダーに移動します

    $ mv  src ../dst
    

    すぐに起こる

  2. srcフォルダー内でこれを実行して移動します。

    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ {} +
    

    これには時間がかかります。

2番目のプロセスをスピードアップする方法はありますか?


1
解決策ではありませんが、明確にするために、cmd2はcmd1よりも遅くなければなりません。findを使用し、結果の移動を実行します。これは、事前検索プロセスなしの直接移動ほど高速になることはありません。
ダフテ

おそらくdstパーティションにあるのに対して../../dst、別のパーティションにあります。
phuclv

書かれているように、これは有効な検索呼び出しのようには見えません。{}ファイル名を展開する引数がありません。
R ..

タイトルを変更し、「画像」への参照を削除し、問題の塊に置き換える編集を送信しました。個々のファイルを移動するのとフォルダー全体を移動するのです。担当者の誰かがそれを受け入れてくれることを願っています。
モンティハーダー

1
の有効な呼び出しではありませんfind。ファイルごとに1回find ... -exec mv -t ../../dst/ {} \;呼び出しmvます。find ... -exec mv -t ../../dest {} +呼び出しごとにできるだけ多くのファイルをコピーしますが、dadexix86で説明されているようにディレクトリ自体を移動するほど高速ではありません。
-chepner

回答:


50

TL; DR:いいえ

ファイルの量が少ない場合は、必要ありません findが、この単純化された小さい場合でも、

mv *.jpg ../../dst/

ディレクトリ全体を一度に移動するよりも時間がかかります。


どうして?ポイントは何をするかを理解することmvです。

簡単に言えば、mv番号(ディレクトリまたはファイルを識別する)をiノード(それを含むディレクトリ)から別のiノードに移動すると、これらのインデックスはファイルシステムのジャーナルまたはFAT(ファイルシステムの場合)そのような方法で実装されます)。

コピー元とコピー先が同じファイルシステム上にある場合、データの実際の移動はなく、それらが接続されている位置を変更するだけです。

したがって、ディレクトリをmv 1つすると、この操作を1回実行します。

しかし、100万個のファイルを移動すると、この操作は100万回実行されます。

実用的な例を挙げると、多くの枝を持つツリーがあります。特に、100万のブランチが接続されている1つのノードがあります。
これらのブランチを切り取って別の場所に移動するには、それぞれをカットして100万回カットするか、ノードの直前でカットして1回だけカットします(これはファイルの移動とディレクトリ)。


4
mv同じファイルシステム上のaが単なるTOCエントリの書き換えであることを含める必要があります。
Videonauth

TOCの意味を理解しているかどうかはわかりません。私の知る限り、extファイルシステム、NTFS、またはbtrfsなどにはテーブルがありません。FATにはテーブル(名前の取得元)がありますが、たとえば、extは名前とブロック、親、子、および他の情報をiノードに格納します。ext FSのTOCがどこにあり、何に使用されるかを説明しているリファレンスを参照できる場合は、喜んで答えを読んで更新します:)
dadexix86

10
あの mv *.jpg1200万個のファイルで失敗する可能性が高いため、findを使用します。ほとんどのUnix、Linuxには、コマンドラインの最大長が限られている(過去5〜10年で誰かが変更していない限り)と信じています。Linuxでは64Kだったと思う。同じ制限が環境変数にも当てはまります。
ザンリンクス

1
ファイルの移動とは、ファイルの名前を移動することです。Unixライクなディレクトリエントリには、ファイル名とiノード番号が含まれています。これは基本的に、残りのメタデータへのポインタです。ディレクトリは特別な種類のファイルです。iノード自体には、ファイルの実際のデータは含まれておらず、それへのポインタだけが含まれているため、iノードから何かが移動されたと言うのは少し誤解を招きます。一方、ファイルシステムジャーナルは通常、主にクラッシュ防止に使用されるメタデータログのタイプを参照します。
イルカチュウ

1
もちろん、ここでの用語は重要なポイントではありません。重要なことはまさにあなたが言ったことです:ファイルシステム内では、動きはメタデータに触れるだけです。あるファイルシステムから別のファイルシステムに、ショートカットはなく、すべてのファイルはその内容も含めて1つずつ移動(再作成)する必要があります。その場合、ディレクトリ全体を移動するのか、内部のファイルだけを移動するのかは関係ありませんが、ほぼ同じくらい遅くなります。
-ilkkachu

13

前述のように、ファイルシステムは各ファイル名を新しい場所に再リンクする必要があるため、依然として低速です。

ただし、現在の状態からスピードアップできます。

findコマンドは、ファイルごとに1回execを実行します。したがってmv、1200万のファイルに対してコマンドを1200万回起動します。これは2つの方法で改善できます。

  • 最後にプラス記号を追加
    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ +
    しますfind。マンページをチェックして、バージョンのでサポートされていることを確認します。効果はmv、各コマンドラインに収まるだけのファイル名で一連のコマンドを実行することです。

  • 使用findxargs一緒に。ファイル名を区切るためにゼロバイト別名、NULを使用します。これに加えて、ファイル名にスペースがある場合に発生する問題を修正します。コマンドは、からファイル名のリスト読み込みますコマンドを実行してフィットするよう、多くのファイル名として上でコマンドを。
    find -maxdepth 1 -name '*.jpg' -print0 | xargs -0 mv -t ../../dst/
    -print0xargs -0xargsxargsfindmv


7

混乱は、ファイルシステムの抽象化から生じます。この抽象化により、フォルダにはファイルや他のフォルダがツリー状に含まれていると思われます。これは実際には正しくありません。ファイルシステム内のすべてのファイルとディレクトリは同じレベルにあり、実装に応じて何らかの番号で識別されます。ディレクトリは、他のファイルのリストを含む特別なファイルです。

ファイルシステム内でファイルを「移動」すると、実際のファイルはどこにも移動しません。むしろ、ディレクトリ内のリストは変更を反映するために更新されます。

mv src ../dst単一のリストエントリをディレクトリからディレクトリ.に移動する../dstため、高速です。

find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/何百万ものエントリを移動する必要があるため、処理が遅くなります。mvファイルごとに一度ではなく一度だけ呼び出すと潜在的に高速化される可能性があり、mvコマンド自体は複数のディレクトリエントリを1ステップで移動するように最適化される場合がありますが、単一のディレクトリを移動するときほど高速にする方法はありません。


4

簡単な答え

ファイルの移動は3つのステップで完了します。

  • ファイルへのリンクを宛先フォルダーのiノードリストに追加します
  • リンクが正常に追加されたかどうかを確認します
  • 上記のチェックが成功した場合、ソースフォルダーのiノードのリストからリンクを削除します。

このプロセスは、ファイルまたはフォルダーの場合と同じです。
そして、明らかに1つのファイルに対してこれを行うことは、100個のファイルに対して行うよりも100速いです。

man link add()
man unlinkはremove ()であり、
mv上記の2つのコマンドを使用して、データの損失を防ぐためにチェックを追加します。


1
まあ、rename()もあります。
-ilkkachu
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.