コネクションとメモリのプール
むむ。aio_read(POSIX AIO)はダメかも。どうしよう。
POSIX AIOはIOが完了したときにスレッドを立ち上げて関数を実行してくれるけど、そのスレッドはユーザーランド(Linuxならlibrtの中)で立ち上げているっぽい。スレッドプールもしてくれない。
うーむ。それはどうなんだ。
clone()はfork()ほど重くないとしても、最初から起動しておいた方が速そうな気がする。
むむ。
1. もう作ったからPOSIX AIOでいい
2. V-FIELD時代に戻ってselect()+自前のスレッドプール
3. とりあえずpoll+自前スレッドプールで作って、後でepoll/kqueueに変更する
4. pollもepollもkqueueも使える汎用インターフェースを作ってから、とりあえずpollで実装
5. POSIX AIOでもスレッドの通知は使わないで、aio_suspend()する
やるなら4か…libeventというライブラリを使っても良いのだけど、どうもインターフェースが気に入らない。
kqueueはまだ調べてないけど、レベルトリガならepollは普通に使えそう。EPOLLONESHOTを使えば、ほとんどロック無しで使える。これは良い。
aio_suspend()は無いな。epoll + splice + vmspliceの方が速いと思う。Linux(しかも2.6.17以上)依存は、とりあえず気にしない方向で。でもMacでコンパイルできないのは困るかな…
そのsplice + vmspliceも、データの受け取り側ではそんなに速くないっぽい。read + writeでも十分速い。
http://lkml.org/lkml/2006/11/22/40
このあたり、socketからのreadに関してはカーネル内でかなりの最適化が効いているのかもしれない。
(送信側はsplice + spliceがかなり効くっぽい。でもこっちはsendfile()で良い気がした)
ただsocketからreadすると、別にメモリを確保しておかないといけない。
write chainでは、障害に備えて/ディスクには非同期IOのため/buffered_writeのため/atmic_writeのために、回している最中のデータは全部保持していないといけないけど、いちいちバッファをnewしていたら重い。
で、メモリプールを使おうと思うのだけど、マルチスレッドのメモリプールはそんなに速くないらしい。ロック重い。
一方、シングルスレッドのメモリプールはなにやらとても速いらしい。『Efficient C++』より。
というわけで、メモリプール付きスレッドプールを作れば良いんじゃないかと思った。プールされたスレッドごとに、メモリプール
が付いている。
流行の富豪的プログラミングですよ。スレッド8つプール×16KBのメモリを16個プール。全然問題ないよね。