2013-03-03 13 views
33

Real World Haskell, Chapter 28, Software transactional memoryには、同時ウェブリンクチェッカーが開発されています。それはウェブページ内のすべてのリンクを取得し、HEADリクエストで1回ずつヒットし、リンクがアクティブかどうかを判断します。純粋なHaskellコードにはスレッドプールが必要ですか?

URLごとに1つのスレッドを作成するだけでは、CPUやネットワーク接続に負荷がかかる可能性があるため、リンクのほとんどは生き生きと応答しています。代わりに、キューからダウンロードするためにURLをフェッチする固定数のワーカースレッドを使用します。

各リンクにforkIOを使用する代わりに、このスレッドプールが必要な理由を完全に理解できません。 AFAIK、Haskellランタイムはスレッドのプールを維持し、適切にスケジューリングするので、CPUが過負荷になることはありません。さらに、a discussion about concurrency on the Haskell mailing listに、私は同じ方向に行く次の文を見つけました:(RTSは、私たちのためにその をしているので)Haskellでは意味がありません

1つのパラダイムは、ワーカースレッドです。ワーカーをフェッチするのではなく、代わりにforkIOを使用します。

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

+9

プールは、並行性のレベルを制御し、管理するために必要です。実用的な考慮事項はおそらく忘れているでしょう。ハスケルランタイムは、実際にはハスケルスペーススレッドを維持するのには非常に優れています。それらはかなり軽量であり、何千もの問題は発生しません。しかし、100KのURLのリストを取得し、「プールする」ことなく1つずつforkIOするとどうなりますか?あなたは何千もの接続を何千も作るでしょう。多くの場合、タイムアウトになります。システムはファイル記述子を使い果たし、結果を処理しようとするとRAMが不足する可能性があります。 – ozataman

答えて

23

コアの問題は、私が想像しているように、ネットワーク側です。リンクごとに10,000のリンクとforkIOがある場合は、一度に開くしようとしているソケットが10,​​000個ある可能性があります.OSの設定によっては、おそらくそれほど効率的ではありません。

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

ほとんど問題が並行していないとしても、実際にはではありません。可能な限り小さく分割してやり直してくださいそれは「一度に」。

+0

ハハ!私たちが正確に同じ時間に(15秒以内に)コメント/回答したように見えます! – ozataman

+0

キャッシュからレジスタへデータをプルすることは、シングルスレッド内でキューに入れるときにも必要です。私はスレッドのハウスキーピングのオーバーヘッドがこのケースでより重要であると感じています。 – leventov