34

Real World Haskellの第28章、ソフトウェアトランザクショナルメモリでは、同時Webリンクチェッカーが開発されています。Webページ内のすべてのリンクをフェッチし、それらのすべてをHEADリクエストでヒットして、リンクがアクティブかどうかを判断します。このプログラムを構築するために並行アプローチが採用され、次のステートメントが作成されます。

URLごとに1つのスレッドを作成することはできません。これは、(予想どおり)ほとんどのリンクがライブで応答性が高い場合、CPUまたはネットワーク接続に負担がかかる可能性があるためです。代わりに、キューからダウンロードするURLをフェッチする固定数のワーカースレッドを使用します。

forkIOリンクごとに使用する代わりに、このスレッドプールが必要な理由を完全には理解していません。AFAIK、Haskellランタイムはスレッドのプールを維持し、それらを適切にスケジュールするので、CPUが過負荷になっているのはわかりません。さらに、Haskellメーリングリストでの並行性についての議論で、私は次のステートメントが同じ方向に進んでいることを発見しました。

Haskellで意味をなさない1つのパラダイムは、ワーカースレッドです(RTSが私たちのためにそれを行うため)。ワーカーをフェッチする代わりに、代わりにforkIOを取得します。

スレッドのプールはネットワーク部分にのみ必要ですか、それともCPUの理由がありますか?

4

1 に答える 1

23

中心的な問題はネットワーク側だと思います。10,000 個のリンクと各リンクの forkIO がある場合、一度に 10,000 個のソケットを開こうとしている可能性があります。これは、OS の構成方法によっては、おそらく不可能であり、はるかに効率的ではありません。

ただし、複数の OS スレッド (理想的には個々のコアに固定されている) にわたって「仮想的に」スケジュールされるグリーン スレッドがあるという事実は、CPU 使用率に関係なく作業をランダムに分散できるという意味ではありません。ここでの問題は、CPU 自体のスケジューリングが処理されないということではなく、コンテキスト スイッチ (緑色のスイッチであっても) にサイクルがかかるということです。各スレッドが異なるデータを処理している場合、そのデータを CPU に取り込む必要があります。十分なデータがある場合、それは CPU キャッシュに出し入れすることを意味します。それがなくても、キャッシュからレジスターなどに物事をプルすることを意味します。

問題が自明な程度に並列化されている場合でも、それをできるだけ小さく分割して「一度に」実行しようとすることは、事実上決して正しい考えではありません。

于 2013-03-04T04:47:53.163 に答える