0

Parallel.ForEach の使用に問題があります。着信接続を待機して応答する、いくつかのハードウェア コンポーネントをシミュレートする必要があります。

私の現在のコードは次のとおりです。

Task.Factory.StartNew(() => components, (component) =>
    {
        var listener = new TcpListener(component.Ip, component.Port);
        while(true)
        {
            using(var socket = listener.AcceptSocket())
            {
                 //Read out socket and send a reply
                 socket.Close();
            }
        }
    });

私が抱えている問題は、すべてのコンポーネントが独自のスレッドを作成するわけではないということです。スレッドの 1 つが終了しても、それらはまだ生成されません。

コレクション内のコンポーネントの現在の量は 40 で、生成されたスレッドの数は 33 (または少なくともそのように見える) です。

Parallel.Foreach() は、渡された列挙可能なコレクション用の新しい並列スレッドを作成するという印象を受けました。

私が間違っていることはありますか?

4

1 に答える 1

3

各タスクのすべてのスレッドを一度に開始するとは限りません。ワークロードを調べ、プロセッサのすべてのコアにわたってそれをプロビジョニングします。コアよりも多くのタスクがある場合、新しいスレッドの作成が停止されます。これは、多くの不要なコンテキストの切り替えにつながるためです。ただし、既存のタスク/スレッドがブロックされていると判断した場合は、スレッドを追加して作業を継続できるようにします。つまり、他のタスクがブロックされている間、より多くのタスクを開始します。ブロックされたタスクは、短期間検出されません。

これはおそらく、タスクと同じ数のスレッドが表示されない理由を説明しています。タスクが終了すると、システムはそれがあったスレッドを再利用して、まだ開始されていない新しいタスクをそのスレッドに置くことができます。

このブログ投稿の下部にあるグラフは、これをある程度示しています。最大 4 つのタスクを実行すると、1 つだけの場合とほぼ同じ時間がかかりました。その後、5 番目のタスクが追加されたときにジャンプがあり、完了するまでにかかった時間は、再びジャンプした 8 番目のタスクまでほぼ同じでした。これは、私が 4 コア システムを使用していたためです。

アップデート

そこに無限ループがあるため、コードがタスクを終了しないことに気付きました。タスク (個別の作業単位) は、あなたが望むものではないと思います。Task Parallel Library から特別に取得するものが他にない限り、この場合は通常のスレッドを自分で使用する方が良い解決策になる可能性があります。

タスクでは、スレッドがいつ作成されるか、または一度にいくつスレッドが作成されるかをほとんど制御できません。(保持したい TPL から他のものを取得する場合は、独自のスケジューラを記述してこれを制御できます)。ただし、アプリケーションの存続期間中常に何かをリッスンするバックグラウンド スレッドを単純に開始する場合は、通常のスレッドを使用します。

于 2013-01-31T09:15:43.963 に答える