質問

学生レコードが含まれているサイズ2GBのファイルがあります。各レコードの特定の属性に基づいて生徒を見つけ、結果を伴う新しいファイルを作成する必要があります。フィルター処理された学生の順序は、元のファイルと同じである必要があります。メモリの問題を抱えずにJava IO APIとスレッドを使用して、これを行う効率的かつ最速の方法は何ですか? JVMのMaxHeapサイズは512MBに設定されています。

役に立ちましたか?

解決

  1. ファイルの2GBは巨大です。DBを使用する必要があります。
  2. 本当に使いたいなら Java I/O API, 、次にこれを試してみてください: Javaで大規模なデータファイルを効率的に処理します この: Java I/Oパフォーマンスのチューニング

他のヒント

どんなファイル? CSVのようなテキストベース?

最も簡単な方法は、grepが行うようなことを行うことです。線ごとにファイルを読み取り、ラインを解析し、フィルター基準を確認し、一致する場合は結果行を出力し、ファイルが完了するまで次の行に移動します。これは非常にメモリ効率的です。現在のライン(またはバッファーが少し大きい)のみが同時にロードされているため、非常に効率的です。あなたのプロセスは、ファイル全体を一度だけ読む必要があります。

複数のスレッドがあまり役に立つとは思わない。それは物事をはるかに複雑にするでしょう、そして、プロセスはとにかくI/Oバインドされているように見えるので、複数のスレッドで同じファイルを読み込もうとすることはおそらくスループットを改善しません。

これを頻繁に行う必要があり、毎回ファイルを通過する必要がある場合は、遅すぎる場合は、何らかのインデックスを構築する必要があります。それを行う最も簡単な方法は、ファイルを最初にDB(SQLiteやHSQLのような埋め込みDB)にインポートすることです。

あなたがあなたが必要とするもののために退屈な単純な方法が機能しないことがわかるまで、私はこれを過度に複雑にしません。基本的にあなたはただする必要があります:

  • 2GBファイルに入力ストリームを開き、バッファーを覚えています(例:bufferedinputStreamでラッピングして)
  • 作成するフィルタリングされたファイルへの出力ストリームを開く
  • 入力ストリームから最初のレコードを読むには、「必要」かどうかを決定するための属性を見てください。もしそうなら、それを出力ファイルに書き込みます
  • 残りのレコードのために繰り返します

非常に控えめなハードウェアを備えた私のテストシステムの1つで、FileInputStreamの周りのBufferedInputStreamで25秒で約500 MBを読み取ります。つまり、おそらく2GBファイルを処理するために2分未満で、デフォルトのバッファサイズは基本的に良いものです(を参照してください BufferedInputStreamタイミング 詳細を作成しました)。最先端のハードウェアでは、時間が半分になる可能性があると思います。

2/3分を削減するために多大な努力をする必要があるか、それが実行されるのを待っている間にちょうどおしっこをする必要があるかどうかは、要件に応じて行う必要がある決定です。データベースオプションは、同じデータセットで多くの異なる処理を実行する必要がない限り、あまり購入しないと思います(そして、これには自動的にデータベースを意味しない他のソリューションがあります)。

使用する必要があると思います メモリマッピング ファイル。これは、より大きなファイルを小さなメモリにマッピングするのに役立ちます。これは仮想メモリのように機能し、パフォーマンスに関する限り、マッピングされたファイルはストリーム書き込み/読み取りよりも高速です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top