2012-01-26 30 views
1

私は何千ものファイルをインポートするc#(.Net 3.5)アプリケーションを持っています。今、私は各ファイルのバックグラウンドワーカーを作成します。特定の限界までは正常に動作します。&アプリケーションがメモリ不足システム例外で終了します。私はスレッドの数が多いので、これが起こっていると仮定しています。スレッドプールはこの状況に適したソリューションですか?マルチスレッド - スレッドプールは適していますか?

例外は次のとおりです。

System.OutOfMemoryException | Exception of type 'System.OutOfMemoryException' was thrown. 
    at System.Data.RBTree`1.TreePage..ctor(Int32 size) 
    at System.Data.RBTree`1.AllocPage(Int32 size) 
    at System.Data.RBTree`1.InitTree() 
    at System.Data.Index.InitRecords(IFilter filter) 
    at System.Data.Index..ctor(DataTable table, Int32[] ndexDesc, IndexField[] indexFields,   
    Comparison`1 comparison, DataViewRowState recordStates, IFilter rowFilter) 
    at System.Data.DataTable.GetIndex(IndexField[] indexDesc, DataViewRowState recordStates, IFilter 
    rowFilter) 
    at System.Data.DataColumn.get_SortIndex() 
    at System.Data.DataColumn.IsNotAllowDBNullViolated() 
    at System.Data.DataTable.EnableConstraints() 
    at System.Data.DataTable.set_EnforceConstraints(Boolean value) 
    at System.Data.DataTable.EndLoadData() 
    at System.Data.Common.DataAdapter.FillFromReader(DataSet dataset, DataTable datatable, String  
    srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn  
    parentChapterColumn, Object parentChapterValue) 
    at System.Data.Common.DataAdapter.Fill(DataTable[] dataTables, IDataReader dataReader, Int32 
    startRecord, Int32 maxRecords) 
    at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 
    startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior) 
    at System.Data.Common.DbDataAdapter.Fill(DataTable[] dataTables, Int32 startRecord, Int32 
    maxRecords, IDbCommand command, CommandBehavior behavior) 
    at System.Data.Common.DbDataAdapter.Fill(DataTable dataTable) 
    at Dms.Data.Adapters.DataTableAdapterBase`2.FillByCommand(TTbl table, DbCommand command) 
+0

どの言語/フレームワークですか? –

+0

質問が更新されました。そのC#で。どうも。 – Rik

+0

アプリケーションが32ビットで、1より大きい値をロードする場合。メモリに5 GBのデータがある場合、おそらくメモリ不足の例外が発生します。詳細については、この質問を参照してください:http://stackoverflow.com/questions/1109558/allocating-more-than-1-000-mb-of-memory-in-32-bit-net-process一度に1.5 GBのデータ? – Kiril

答えて

4

問題は、あなたが時間を一度にあまりにも多くのファイルをロードしようとしている可能性が最も高いです。

ThreadPoolを使用すると、処理を制限する手段が得られる可能性があります。しかし、「何千ものファイル」をインポートして処理している場合は、処理を処理するパイプラインを作成し、パイプライン(またはそれらのうちのいくつか)をファイルに埋め込むことが適切な手段です。これにより、並行処理の量を制御し、同時に多くの個々のファイルが処理されるのを防ぐことができます。メモリと処理要件をより合理的なレベルに保つことができます。


編集:あなたは(今)あなたはC#を使用している... BackgroundWorkerのは、実際のThreadPoolを使用しないことを述べているので

。スレッドプールを直接使用することをお勧めしますが、問題を完全には解決できない可能性があります。プロデューサ/コンシューマキューを設定するには、BlockingCollection<T>のようなものを使用することを検討してください。その後、1つ以上のスレッドがファイルを「消費」して処理し、すべてのファイルをBlockingCollection<T>に追加することができます。これにより、一度に処理されるファイル数を制御できます(できるだけ処理するために別のスレッドを追加するだけです)。

+0

+1 を推奨します。ユーザーにとってよりスマートな選択(彼がすべてを正しく記述している場合) –

1

はい、可能です。限られた数のCPUまたはコアしかないと考えてください。そのスレッドだけが同時に実行できます。 を有効にしてとすることができます。たとえば、これらのファイルをダウンロードしている場合など、別のコンピュータで実行されている他のプロセスを待っている人が多数います。別のスレッドを持っているからといって、並行性が増しているわけではありません。ちょうどコストを切り換えて、メモリの割り当てを(見たように)。アイドル時間の量に応じて、プールをcpusよりわずかに多くスレッドに制限してみてください。そこから微調整する。

+0

ファイルをインポートするときに、他のプロセスを待つ必要があると考えます。ユーザーはtxtファイル名を入力して、すべてのファイルをその位置とともに一覧表示します。アプリケーションはこのファイルを1行ずつ解析し、各ファイルは指定された場所から読み取られ、アプリケーションデータベースにコピーされます。これは私のシナリオを明確にしていますか? – Rik

+0

私の答えは一般的でした。私はあなたが使っていた言語やフレームワークを知らなかった。私はC#に精通していません。スレッドモデルは言語に依存しませんが、他のレスポンダに示されているように、同じ言語を使ってデザインをやりとりすることは素晴らしいことです。つまり、プールとパイプラインの違いはあまりないかもしれません。ボス/ワーカーは効果的にプーリングしています。いずれにせよ、あなたは有限のリソースを通して多くの別々の仕事を集めています。一般的に言えば(価値があるものについては)、アプリケーションの構造に適合するモデルほど重要ではありません。 – joe

1

良い選択だと思います。しかし、バックグラウンドワーカーは、.Net 4 framworks tasksによっていくらか置き換えられました。これは、あなたのマシン上のプロセッサの数に基づいて最適化し、それに応じてワークアウトを実行します。おそらくあなたはTPLを使用して、平行してforを使用することができます。あなたは、例えば、バッチで、一度にインポートするファイルの数を制限するために実行する同時スレッドプールのスレッドの最大数を渡すことができます。:

ParallelOptions options = new ParallelOptions(); 
options.MaxDegreeOfParallelism = 4; 

Thisあなたを助けるかもしれませんか?

0

あなたが理解しているとすれば、プロデューサー - コンシューマーアプローチを実装する必要があります。 1)1人のプロデューサー - ファイルリストを作成します(インポートする)。 2)複数の(固定数の)コンシューマ - インポートを実行します。

これを実現するには、BlockingCollection(.NET 4.0以降)を使用します。ドキュメントには例があります。

+0

BlockingCollectionは.net 4.0で利用可能です。私は.net 3.5で作業しています。しかし、同時に実行しているバックグラウンドワークの数を制限すれば、それは役に立ちますか? – Rik

+0

何も問題はありません。ブロッキングキュークラスの実装についてはこちらをご覧ください: http://stackoverflow.com/questions/530211/creating-a-blocking-queuet-in-net –

関連する問題