1

質問:

  • 主な質問: これらの仕事を並行させるための最善の戦略は何ですか?
  • アイデア: 2 番目のチェックサム (Adler32?) などの他のメカニズムを使用してプロセスを高速化する方法

シナリオ:

Javaで一種の同期ツールを書いています。基本的に、ローカル マシン上のファイル/ディレクトリ構造を表す Web サーバーからリポジトリをダウンロードし、必要なファイルのソースをハッシュ値と組み合わせて圧縮形式で定義し、ファイルを検証します。私が推測する基本的なこと。

要件:

  • マルチプラットフォーム Java デスクトップ アプリケーション
  • 可能な限り最高の速度と並列化

構造の例: (ゲームのモッズを使用して最もよく説明されています)

リポジトリ ファイルの例

{"name":"subset1", "mods":[
    {
        "modfolder":"mod1",
        "modfiles":[
            {
                "url":"http://www.example.com/file2.7z",
                "localpath":"mod1/file2",
                "size":5,
                "sizecompressed":3,
                "checksum":"46aabad952db3e21e273ce"
            },
            {
                "url":"http://www.example.com/file1.7z",
                "localpath":"mod1/file1",
                "size":9,
                "sizecompressed":4,
                "checksum":"862f90bafda118c4d3c5ee6477"
            }
        ]
    },
    {
        "modfolder":"mod2",
        "modfiles":[
            {
                "url":"http://www.example.com/file3.7z",
                "localpath":"mod2/file3",
                "size":8,
                "sizecompressed":4,
                "checksum":"cb1e69de0f75a81bbeb465ee0cdd8232"
            },
            {
                "url":"http://www.example.com/file1.7z",
                "localpath":"mod2/file1",
                "size":9,
                "sizecompressed":4,
                "checksum":"862f90bafda118c4d3c5ee6477"
            }
        ]
    }
]}

同期後のクライアント ファイル構造

    mod1/
         file2
         file1
    mod2/
         file3
         file1

// mod1/file2 == mod2/file2

リポジトリに関する特別な点: サーバーから取得したリポジトリは、より大きなリポジトリのサブセットのみを表します。これは、ユーザーが必要とするのはサブツリーのみであり、変更されています (これも重複しています)。リポジトリが mod1 と mod2 で構成される場合もあれば、mod1 と mod3 で構成される場合もあります。

やるべきこと:

  • リポジトリをダウンロードして解析する (Net I/O)
  • リポジトリにないファイルをプロセスの最後に削除するようにマークします (ファイルは同じチェックサムのためにコピーされる可能性があります) (ファイル I/O)
  • ファイルが存在する場合:既存ファイルのチェックサムチェック(チェックサムキャッシュ)(ファイルI/O)
  • ファイルが存在しない場合: checksumcache で他のサブツリーにある同一のファイルをチェックして、ファイルをダウンロードする代わりにコピーします (ファイル I/O の軽量化)。
  • 単一ファイルを圧縮形式でダウンロード (Net I/O)
  • 圧縮ファイルの抽出 (ファイル I/O)
  • 非圧縮ファイルのチェックサム (ファイル I/O)
  • ファイルに関連付けられたキャッシュ チェックサム。(ライトファイルI/O)

私の解決策:(多くの異なる生産者/消費者)

  • チェックサム キャッシュは、MapDB の永続的なマップを使用しています。
  • ATM のみ md5 チェックサムが使用されます。
  • キュー: すべての Workertype にはブロッキング キュー (プロデューサー/コンシューマー) があります。
  • スレッドプール: すべてのワーカータイプには、3 つのダウンローダー、2 つのチェックサムなど、固定のスレッドプールがあります。
  • ワーカーは現在のジョブを他のキューに配布します: Downloader -> Extract -> Checksum

ワーカータイプ:

  • Localfile Worker: ローカル ファイル構造をチェックし (チェックサム キャッシュを使用)、作業を Download-Worker、Delete-Worker にリダイレクトします。
  • コピー: チェックサムが同じファイルを宛先にコピーします。
  • ダウンロード: ファイルをダウンロードします
  • チェックサム: ファイルのチェックサムと checksumcache への挿入
  • 削除: ファイルを削除します
  • 抽出: 圧縮ファイルを抽出します
4

1 に答える 1

2

これらの仕事を並行させるための最善の戦略は何ですか?

I/O があります。また、おそらく、あるディレクトリで 1 つのジョブがすでに進行中の場合、同じディレクトリで別のジョブを同時に実行することはできません。

したがって、ここでロックする必要があります。推奨事項: ファイルシステムでロック ディレクトリを使用し、ファイルではなくディレクトリを使用してロックします。なんで?ディレクトリの作成はアトミックであるため (最初の理由)、Java 6 はアトミック ファイルの作成をサポートしていないためです (2 番目の理由)。実際には、2 つのロック ディレクトリが必要になる場合もあります。1 つはコンテンツのダウンロード用、もう 1 つはコンテンツの処理用です。

ダウンロードと既に行った処理の分離なので、ここでこれ以上言うことはありません ;)

しかし、なぜチェックサムをキャッシュしたいのかわかりませんか? 私にはあまり役に立たないように見えます...

また、対処しなければならないファイルの大きさはわかりませんが、新しいディレクトリを抽出して名前を変更するのではなく、既存のディレクトリの内容などを確認するのはなぜですか? すなわち:

  • で新しいディレクトリを抽出しnewdirます。
  • チェックサム;
  • に移動dstdirdstdir.oldます。
  • に移動newdirdstdirます。
  • スクラップdstdir.old

これは、スクラップを並列化できることを意味しますが、それは多すぎる I/O 並列化です...実際の I/O を実行するスレッドの数を制限する必要があります。

EDIT処理を分離する方法は次のとおりです。

  • まず第一に、アーカイブ自体にはもうチェックサムはありませんが、アーカイブには各ファイルの MD5 サムを含むファイルがあります (たとえば、MD5SUMS);
  • 2 つのブロッキング キュー: ダウンロード -> 置換、置換 -> 廃棄。
  • 1 つのプロセッサがダウンロードを処理します。完了すると、ダウンロードがいっぱいになります->キューを置き換えます。
  • 別のプロセッサがダウンロードからタスクを選択します -> キューを置き換えます。このタスクは、アーカイブ解除とチェックサムを順番に実行します。両方が正しい場合、上記のように、既存のディレクトリの名前を変更し、抽出されたディレクトリの名前を予想されるディレクトリに変更し、スクラップ タスクを置換 -> スクラップ キューに置きます。
  • 3 番目で最後のプロセッサは、スクラップ キューからタスクを選択し、以前のアーカイブの削除を実行します。

チェックサムがそれほど重い場合は、並列化できることに注意してください。

于 2013-06-19T11:06:06.330 に答える