3

Parallel.ForEach が新しいスレッドを起動しない

みなさん、こんにちは。マイクロソフトの .NET Framework 用 Parallel Extensions の Parallel.ForEach を使用して記述した、非常に IO 集中型の操作があります。大量のファイルを削除する必要があり、削除するファイルをリストのリストとして表します。ネストされた各リストには 1000 個のメッセージがあり、これらのリストは 50 個あります。ここでの問題は、後でログを確認すると、Parallel.ForEach ブロック内で実行されているスレッドが 1 つしかないことです。

コードは次のようになります。

List<List<Message>> expiredMessagesLists = GetNestedListOfMessages();
foreach (List<Message> subList in expiredMessagesLists)
{
    Parallel.ForEach(subList, msg =>
    {
        try
        {
            Logger.LogEvent(TraceEventType.Information, "Purging Message {0} on Thread {1}", msg.MessageID, msg.ExtensionID, Thread.CurrentThread.Name);

            DeleteMessageFiles(msg);
        }
        catch (Exception ex)
        {
            Logger.LogException(TraceEventType.Error, ex);
        }
    });
}

より単純なデータ構造を持ち、IO ロジックを持たないサンプル コードをいくつか書いたところ、Parallel.ForEach ブロック内でいくつかの異なるスレッドが実行されていることがわかりました。上記のコードの Parallel.ForEach で何か間違ったことをしていますか? つまずいているリストのリストである可能性がありますか、それとも IO 操作にある種のスレッド制限がありますか?

4

2 に答える 2

6

いくつかの可能性があります。

まず、ほとんどの場合、Parallel.ForEach新しいスレッドは生成されません。.NET 4 ThreadPool (すべての TPL が使用) を使用し、ThreadPool スレッドを再利用します。

そうは言っても、Parallel.ForEach は、渡される List のサイズに基づいてパーティショニング戦略を使用します。私の最初の推測では、「外側の」リストには多くのメッセージがありますが、内側のリストには Message インスタンスが 1 つしかないため、ForEach パーティショナーは単一のスレッドしか使用していません。要素Parallelが 1 つの場合、バックグラウンド スレッドに作業をスピンさせずに、メイン スレッドを使用するだけで十分スマートです。

通常、このような状況では、内側のループではなく、外側のループを並列化する方が適切です。これにより通常はパフォーマンスが向上します (作業項目が大きくなるため) が、ループのサイズと作業単位のサイズをよく理解していないと判断するのは困難です。潜在的に、内側と外側のループの両方を並列化することもできますが、プロファイルを作成しないと、最適なオプションを判断するのは困難です。

もう1つの可能性:

[Thread.ManagedThreadId][1]ログに Thread.CurrentThread.Name の代わりに使用してみてください。ThreadPool スレッドを使用するためParallel、「名前」は多くの場合、複数のスレッドで同じです。実際には複数のスレッドを使用しているのに、単一のスレッドしか使用していないと思うかもしれません....

于 2009-12-07T17:51:05.940 に答える
1

コードの根底にある前提は、ファイルを並行して削除できるということです。そうではないと言っているわけではありませんが (私はこの問題の専門家ではありません)、ほとんどのハードウェアでそれが不可能であっても驚かないでしょう。結局のところ、これを行うときは、物理オブジェクト (ハードディスク) で操作を実行していることになります。

Personというメソッドを持つクラス があったとしますRaiseArm()。いつでも100 の異なるスレッドを試してみることができますが、一度に 2 つのスレッドしか上げることができません...RaiseArm()Person

私が言ったように、私は間違っているかもしれません。これは私の疑いです。

于 2009-12-07T17:47:42.983 に答える