おそらくあなたはこれに気づいていませんが、Parallel
クラスのメンバーは単にTask
オブジェクトの(複雑な)ラッパーです。ご参考までに、Parallel
クラスは。を使用してTask
オブジェクトを作成しますTaskCreationOptions.None
。ただし、MaxDegreeOfParallelism
タスクオブジェクトのコンストラクターに渡された作成オプションに関係なく、これらのタスクオブジェクトに影響します。
TaskCreationOptions.LongRunning
TaskScheduler
スレッドのオーバーサブスクリプションを使用するとパフォーマンスが向上する可能性があるという、基礎となる「ヒント」を提供します。オーバーサブスクリプションは、I / Oなどの待ち時間の長いスレッドに適しています。これは、単一のコアに複数のスレッド(はい、タスクではなくスレッド)を割り当てるため、待機するのではなく、常に何かを行う必要があるためです。スレッドが待機状態にある間に完了する操作。TaskScheduler
を使用するThreadPool
場合、LongRunningタスクは専用のスレッドで実行されます(タスクごとにスレッドがある場合のみ)。それ以外の場合は、スケジューリングと作業の盗用(とにかくここで必要なもの)を使用して正常に実行されます。
MaxDegreeOfParallelism
実行される同時操作の数を制御します。これは、データが分割されて処理されるパーティションの最大数を指定するのと似ています。指定できた場合、これは、この例のように、最大同時実行レベルがその値に設定されているTaskCreationOptions.LongRunning
タスクと同様に、一度に実行されるタスクの数を制限することです。TaskScheduler
が必要な場合がありParallel.ForEach
ます。MaxDegreeOfParallelism
ただし、このような高い数に等しい値を追加しても、タスクは引き続きによって制御されるため、実際には一度に多くのスレッドが実行されることは保証されませんThreadPoolTaskScheduler
。そのスケジューラーは、一度に実行されるスレッドの数を可能な限り最小限に抑えます。これが、2つの方法の最大の違いだと思います。TaskScheduler
最大限の並列処理動作を模倣し、両方の長所を備えた独自の記述(および指定)を行うこともできますが、あなたが興味を持っていることには疑問があります。
私の推測では、レイテンシーと実行する必要のある実際のリクエストの数に応じて、タスクの使用は多くの(?)ケースでパフォーマンスが向上しますが、最終的にはより多くのメモリを使用することになりますが、並列ではリソース使用量の一貫性が高まります。もちろん、非同期I / Oは、これら2つのオプションのいずれよりも非常に優れたパフォーマンスを発揮しますが、レガシーライブラリを使用しているため、それができないことを理解しています。そのため、残念ながら、どちらを選択しても、平凡なパフォーマンスにとどまります。
本当の解決策は、非同期I/Oを実現する方法を見つけることです。状況がわからないので、それ以上に役立つとは思いません。プログラム(読み取り、スレッド)は実行を継続し、カーネルはI / O操作が完了するのを待ちます(これはI / O完了ポートの使用とも呼ばれます)。スレッドは待機状態ではないため、ランタイムはより少ないスレッドでより多くの作業を実行できます。これは通常、コアの数とスレッドの数の間の最適な関係になります。スレッドを追加しても、パフォーマンスが向上するわけではありません(実際には、コンテキストスイッチングなどの理由で、パフォーマンスが低下することがよくあります)。
ただし、この回答全体は、質問の最終的な回答を決定するのに役立ちませんが、必要な方向性が得られることを願っています。プロファイルを作成するまで、何がより優れたパフォーマンスを発揮するかはわかりません。両方を試さず(LongRunningオプションのないタスクを意味し、スケジューラーにスレッドの切り替えを処理させることを明確にする必要があります)、特定のユースケースに最適なものを決定するためにそれらをプロファイリングすると、売り切れになります。