2014年07月10日
タイトルですべてを語っていますし、http://blog.livedoor.jp/sonots/archives/32645828.html あたりを読むと良いのですがメモ。
最初にまとめると
- CORE::print() を使う場合は 4096 or 8192 byte 以下に収めること
- CORE::syswrite() なら混ざらない
- 男は度胸。flock(2)する
ということです。
これでわかった人は読む必要ありません。
以下蛇足。
はじめに
perl ではファイルハンドルに書き込むときには何も考えずに CORE::print()
を利用しますが、この人はなんかいい感じにバッファリングしたり、長い文字列だったらぶった切ってくれたりしてくれます。
で、普通はバッファリングのことはみんな意識しているので以下のようにヒットアンドアウェイをやったりしますね。close() で自動的に flush されるので、まぁだいたい autoflush(1) しているのと同じでしょうという発想です。
open my $fh, '>>', $file; print $fh $message, "\n"; close $fh;
大抵のケースでは嬉しい事にこれでログが混ざらずに綺麗に見れます。
しかし、超絶に長いメッセージを書き込もうとした場合にこれだと混ざる可能性があります。
分割されてしまうサイズを調べる
超絶長いのがいくつかというとこれまた環境によって異なるのですが、以下のようにするとさくっとわかります。
$ cat > foo.pl my $s = 'a' x (1024 * 100); open my $fh, '>>', "/tmp/$$"; print $fh $s; close $fh; ^D $ strace perl foo.pl 2>&1 | grep write write(3, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 8192) = 8192 write(3, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 8192) = 8192 write(3, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 8192) = 8192 write(3, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 8192) = 8192 write(3, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 8192) = 8192 write(3, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 8192) = 8192 write(3, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 8192) = 8192 ...
とかなって、write(2) が複数回呼ばれていることがわかりますね。
そして、どうやら 8192byte で切られている模様です。*1
こうなると、普通にマルチプロセスで書き込んでいた場合は context switch が発生してログが混ざること請け合いですね。
具体的には以下のようにすると簡単に確認できます。
$ cat > bar.pl my $char = shift || 'X'; my $str = $char x (1024 * 10); # 8096 byte 以上書き込む for (1..1000) { open my $fh, '>>', '/tmp/test'; print $fh $str, "\n"; close $fh; } ^D $ perl bar.pl A &; perl bar.pl B & $ grep A /tmp/test | grep B | wc -l 13
13行ぐらい混ざっちゃったっぽい!
syswrite を使う
print() では混ざっちゃうことが確認できたので、syswirte を使いましょう。
$ cat > hoge.pl my $s = 'a' x (1024 * 100); open my $fh, '>>', "/tmp/$$"; syswrite $fh, $s; close $fh; ^D $ strace perl hoge.pl 2>&1 | grep write write(3, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 102400) = 102400
こうすると、write(2) 一回だけになっていることがわかります。
上記の記事にあるように write(2) 一発は atomic であることがある程度保証されているので、基本的にはこれだけでおっけーでしょう。
ファイルシステムのことを気にしたくないひと
flock(2) しましょう。
まとめ
でかいログを吐かない。
- *1 : ちなみに 4096 の環境もありました。 PERLIOBUF_DEFAULT_BUFSIZ だと思ったけど違うのかな?
コメント一覧
成功挨拶