3

アプリケーションが一連のファイルを処理する必要がある状況があり、この機能を同期的に実行するのではなく、マルチスレッドを使用してワークロードを異なるスレッドに分割したいと考えています。

作業の各項目は次のとおり
です。 1. ファイルを読み取り専用で開く
2. ファイル内の
データを処理する 3. 処理されたデータをディクショナリに書き込む

各ファイルの作業を新しいスレッドで実行したいですか? これは可能で、ThreadPool を使用するか、「作業」の各項目が 30 ミリ秒しかかからないことを念頭に置いて新しいスレッドを生成することをお勧めしますが、何百ものファイルを処理する必要がある可能性があります。

これをより効率的にするためのアイデアは大歓迎です。

編集: 現時点では、これを処理するために ThreadPool を使用しています。処理するファイルが 500 個ある場合、ファイルを循環し、QueueUserWorkItem を使用して各「処理作業単位」をスレッドプールに割り当てます。

これにスレッドプールを利用するのは適切ですか?

4

8 に答える 8

8

この場合ThreadPool.QueueUserWorkItem(...)、スレッドはシステムと.netフレームワークによって管理されます。自分のスレッドプールと噛み合う可能性ははるかに高くなります。したがって、.netが提供するスレッドプールを使用することをお勧めします。とても使いやすいです、

ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod), ParameterToBeUsedByMethod); 

YourMethod(object o){ Your Code here... }

詳細については、リンクhttp://msdn.microsoft.com/en-us/library/3dasc8as%28VS.80%29.aspxをたどってください。

お役に立てれば

于 2010-09-16T11:14:48.597 に答える
2

スレッドを処理したり、スレッド プールを直接管理したりする代わりに、Parallel Extensions (PEX)のような高レベルのライブラリを使用することをお勧めします。

var filesContent = from file in enumerableOfFilesToProcess
                   select new 
                   {
                       File=file, 
                       Content=File.ReadAllText(file)
                   };

var processedContent = from content in filesContent
                       select new 
                       {
                           content.File, 
                           ProcessedContent = ProcessContent(content.Content)
                       };

var dictionary = processedContent
           .AsParallel()
           .ToDictionary(c => c.File);

PEX は、利用可能なコアと負荷に応じてスレッド管理を処理し、ユーザーは目の前のビジネス ロジックに集中できます (うわー、コマーシャルのように聞こえました!)。

PEX は .Net Framework 4.0 の一部ですが、Reactive Framework の一部として 3.5 へのバックポートも利用できます。

于 2010-04-20T09:29:52.980 に答える
2

有限数のスレッド (たとえば 4) を使用し、4 つの作業プールを使用することをお勧めします。つまり、処理するファイルが 400 個ある場合、スレッドごとに 100 個のファイルを均等に分割します。次に、スレッドを生成し、それぞれの作業を渡し、特定の作業が完了するまで実行させます。

一定量の I/O 帯域幅しかないため、スレッドが多すぎてもメリットはありません。また、スレッドの作成にも少し時間がかかることに注意してください。

于 2010-04-20T07:54:08.070 に答える
1

長い目で見れば、スレッドを自分で管理した方が幸せになれると思います。これにより、実行中の数を制御し、ステータスを簡単に報告できるようになります。

  1. 処理を行うワーカー クラスを構築し、結果とステータスを返すコールバック ルーチンを提供します。
  2. ファイルごとに、ワーカー インスタンスとそれを実行するスレッドを作成します。スレッドを に入れますQueue
  3. 同時に実行したい最大数までスレッドをキューから剥がします。各スレッドが完了すると、別のスレッドを取得します。最大値を調整し、スループットを測定します。Dictionary私は実行中のスレッドを保持するために a を使用することを好みManagedThreadIdます。
  4. 早く停止するには、キューをクリアします。
  5. スレッド コレクションをロックして、健全性を維持します。
于 2010-04-20T23:20:42.843 に答える
1

低レベルのスレッド処理の詳細を処理するCCR (Concurrency and Coordination Runtime)を使用することをお勧めします。戦略に関しては、ディクショナリへの書き込み方法によっては、作業項目ごとに 1 つのスレッドが最適なアプローチではない場合があります。ディクショナリはスレッド セーフではないため、激しい競合が発生する可能性があるためです。

CCR を使用したサンプル コードを次に示します。ここではインターリーブがうまく機能します。

Arbiter.Activate(dispatcherQueue, Arbiter.Interleave(
    new TeardownReceiverGroup(Arbiter.Receive<bool>(
        false, mainPort, new Handler<bool>(Teardown))),
    new ExclusiveReceiverGroup(Arbiter.Receive<object>(
        true, mainPort, new Handler<object>(WriteData))),
    new ConcurrentReceiverGroup(Arbiter.Receive<string>(
        true, mainPort, new Handler<string>(ReadAndProcessData)))));

public void WriteData(object data)
{
    // write data to the dictionary
    // this code is never executed in parallel so no synchronization code needed
}

public void ReadAndProcessData(string s)
{
    // this code gets scheduled to be executed in parallel
    // CCR take care of the task scheduling for you
}

public void Teardown(bool b)
{
    // clean up when all tasks are done
}
于 2010-04-20T13:19:54.863 に答える
0

個々のタスクごとに ThreadPool を使用することは、間違いなく悪い考えです。私の経験からすると、これはパフォーマンスを向上させるどころか、パフォーマンスを低下させる傾向があります。1 つ目の理由は、ThreadPool を実行するためのタスクを割り当てるためだけに、かなりの量のオーバーヘッドが必要になることです。デフォルトでは、各アプリケーションには、最大 100 スレッド容量で初期化された独自の ThreadPool が割り当てられます。400 の操作を並行して実行している場合、キューがリクエストで満たされるのにそれほど時間はかかりません。現在、最大 100 のスレッドがすべて CPU サイクルをめぐって競合しています。はい、.NET フレームワークは、キューのスロットリングと優先順位付けで素晴らしい仕事をしますが、ThreadPool は、おそらくあまり頻繁に発生しない長時間実行される操作 (構成ファイルの読み込み、またはランダムな Web 要求) のために残しておくのが最善であることがわかりました。 )。ThreadPool を使用してランダムにいくつかの操作を開始することは、数百の要求を一度に実行するために使用するよりもはるかに効率的です。現在の情報を考えると、最善の行動方針は次のようなものになります。

  1. アプリケーションが要求を投稿できるキューを使用して、System.Threading.Thread を作成します (または SINGLE ThreadPool スレッドを使用します)。

  2. FileStream の BeginRead メソッドと BeginWrite メソッドを使用して、IO 操作を実行します。これにより、.NET フレームワークはネイティブ API を使用して IO (IOCP) をスレッド化および実行します。

これにより、2 つのレバレッジが得られます。1 つは、オペレーティング システムがファイル システム アクセスとスレッドを管理できるようにしながら、リクエストが並行して処理されることです。2 つ目は、大多数のシステムのボトルネックが HDD になるため、カスタムの優先度の並べ替えとスロットリングをリクエスト スレッドに実装して、リソースの使用をより細かく制御できることです。

現在、私は同様のアプリケーションを作成しており、この方法を使用すると効率的で高速です...スレッド化やスロットリングがなければ、アプリケーションは 10 ~ 15% の CPU しか使用していませんでしたが、関連する処理によっては一部の操作で許容できる場合があります。 、アプリケーションが CPU の 80% 以上を使用しているかのように PC が遅くなりました。これはファイル システム アクセスでした。ThreadPool および IOCP 関数は、PC の動作が遅くなっても気にしないので、混乱しないでください。たとえそのパフォーマンスが HDD の豚のようにきしむことを意味するとしても、これらはパフォーマンスのために最適化されています。

私が経験した唯一の問題は、一度に約 35 のストリームを開いているテスト段階で、メモリ使用量が少し高くなった (50 MB 以上) ことです。私は現在、SocketAsyncEventArgsに対する MSDN の推奨事項と同様のソリューションに取り組んでおり、プールを使用して x 数のリクエストを同時に処理できるようにしているため、最終的にこのフォーラムの投稿にたどり着きました。

これが将来の意思決定に役立つことを願っています:)

于 2012-02-28T20:55:42.683 に答える
0

ThreadPool.QueueUserWorkItemそれぞれの独立したタスクを実行するために使用します。何百ものスレッドを作成しないでください。それは大きな頭痛を引き起こす可能性があります。

于 2010-04-20T07:57:27.447 に答える
0

ThreadPool を使用する一般的なルールは、スレッドがいつ終了するか (またはミューテックスを使用してスレッドを追跡するか) を心配したくない場合、またはスレッドの停止について心配したくない場合です。

それで、仕事がいつ終わるか心配する必要がありますか?そうでない場合は、ThreadPool が最適なオプションです。全体的な進行状況を追跡したい場合は、スレッドを停止してから、独自のスレッドのコレクションが最適です。

スレッドを再利用している場合は、一般に ThreadPool の方が効率的です。この質問により、より詳細な議論が得られます。

H番目

于 2010-04-20T07:59:09.883 に答える