現状、1処理が0.0012秒程度で終わるシステムがある。1回の処理は非常に短いが、これが呼ばれる回数は1処理あたり数百万回にも及ぶ。速度がそれなりに求められる案件だ。その中で何度かログファイルに書き出したいタイミングというのがある。それぞれのログファイルに書き出すタイミングは呼び出しの中では1度だけだ。「処理時間が短くて」「回数が多い」のに共有のログファイルに書くというのはなかなか鬼門だ。ファイルに書いている時間に待ち合わせがあると、速度に対してものすごくロスが発生する。普通に普通に共有されているログファイルをロックする方針でやってみる。endendProcess.waitallログファイルにアクセスできるのは1プロセスだけなので、同時にログに書こうとすると待たされることになる。total1分3秒ということでかなり長い。ソケットで投げてみるUNIXドメインソケットにして投げつけてみる。サーバー側が受け取った後の処理はクライアント側の処理時間には影響しないので、サーバーは投げ捨てる。endendクライアントは直接ファイルに書くのではなくUNIXドメインソケットを使う。endendProcess.waitall待ち合わせは全く発生しないわけではない(ソケットを受付てからスレッドに移るまでの間はブロックされる)が、速くなるはずだと思うのだが。total1分33秒。ソケットに接続するコストが高いようだ。並列数としては今回の場合最大24で、繰り返しの間というのは別にソケットをつなぎ直す必要はない設計になっている。そのため、ループの外側に接続を置くことができる。endendProcess.waitall1行入れ替えただけだが、効果てきめん。total今度は0.3秒で終わった。Linuxの場合ソケットへの書き込みはカーネルがバッファするため、この程度の量であればメモリへの書き込みだけで終了する。そのため、かなり高速である。ちなみに、ファイルの場合共有されているファイルをみんなが開いていたらぐちゃぐちゃになってしまうのでこの方法は使えない。その場合は同じ経路から出ていくことになり、ファイルを共有した場合と同じ問題に直面するため、バグになってしまう。PIDを使う私の新しいアイディアは、「ログファイルにPIDを含める」という方法だ。プロセス自体がマルチスレッドになっていなければ、その瞬間には同一PIDのプロセスはそのプロセスしかいないため、そもそもロックする必要がない。ファイルのロックはあくまで「同時に」書かれるから必要になるのであって、どれだけ速くても順次であれば何も問題はないのだ。endendProcess.waitallファイル名にPIDを含めているため、同時に走っている別のプロセスが同じファイルにアクセスすることはない。これは並列化の方法にプロセスを選択している場合だけだが。totalなかなか速い。ソケットとはだいぶ差があるようだ。考えてみればこれもプロセスをオープンしてからであればなにもループのたびに開き直す必要はない。そこで、ソケットと同じく順序を入れ替えてみる。endendProcess.waitallループのたびにファイルを開くのではなく、予めファイルを開いてループで書いていくようにした。totalファイルとソケットのオープンコストの差か、ソケットよりも速くなった。ちなみに、ソケットを一回だけ開く方法よりも速い。「forkでの並列処理に追記のログファイルはファイル名にPIDで」、このテクニック、私はどこかで見た記憶はないのだが、かなり有用だと思う。