あどけない話

インターネットに関する技術的な話など

Haskellでサーバーを書く

Haskellでメール関連のサーバーを書いていて、いろいろ調べました。かなりがっかりな結果ですが、包み隠さず書きます。

forkIO

forkIO でユーザースレッドを作ると、内部では select() を使います。select() はファイル記述子を 1024 までしか扱えないという壁があって、使い物になりません。(せめて poll() を使って欲しいなぁ。)

世の中には行儀が悪いクライアントが多く、コネクションをリセットします。すると、ハンドルが失われ、明示的に hClose できません。ですから、ソケットの開放は、ガベージコレクション任せとなります。結局、1024 個のソケットを簡単に使い切ってしまうということです。

追記:GHCガベージコレクションは優秀で、ソケットはすぐに回収されることが分かりました。

forkOS

forkOS ではカーネルスレッドを作ります。内部では pthread_create() を使います。スレッドのスタックの大きさと、利用できるメモリーから、作成できるスレッドの数が決まります。さんざん探したのですが、スレッドのスタックの大きさを変更する方法が見つからず、小さい数のスレッドしか作れないので、使い物になりません。

これを超えられても、select() の壁が待っています。

deamonize

System.Posix.Daemonize の deamonize は、forkProcess を2回呼ぶことで、プロセスを端末から切り離します。

forkProcess は、ghc -threaded でリンクされたランタイムの IO スレッドを殺します。ですので、ghc -threaded でコンパイルしたプログラムでは、daemonize を呼んだ後から、IO がおかしくなります。

forkProcess

結局、残された道は、forkProcess を使うことです。

Haskell が得意なスレッド間通信が使えず、かっこ悪いのですが、これなら daemonize とも相性がいいです。

forkProcess の前に、設定ファイルを解析したつもりでも、遅延評価されるかもしれません。よって、設定ファイルの解析は、正格評価にしておく必要があります。

まとめ

現在の GHC では、スレッドを使うと、ちゃんとしたサーバーは書けません。