[flock] バッファ操作関連のまとめ

メッセージ

flock()周辺のバッファ操作(バッファのon/off、フラッシュ等)について、本来どのようにするべきであるかをシチュエーション別に明確にしましょう。

参考文献: set_file_buffer()

PukiWiki 1.4.x は少なくともPHP4.1.2以降ターゲットにしているため、stream_set_write_buffer() ではなく set_file_buffer() を使用しています。

参考文献: fflush()

ステータスキャッシュ関連

ファイル操作上のステータスキャッシュの問題 (このページと直接は関係ない)


(BugTrack2/151より移動)

コメント: バッファ操作?


(BugTrack2/151)

コメント: fputs()のコール回数を減らす案

(STACK*の) set_file_buffer($fp, 0) の説明に疑問...

長文で申し訳ありません. 引用されている set_file_buffer($fp,0) の説明に 疑問を感じたため、手元で確認した結果をこちら記載します. 検証方法の不備や、さらに提供すべき設定内容があれば、お知らせください - jjyun 2006-03-26 (水) 23:36:15

上には set_file_buffer() の説明として以下のような記述が掲載されていますが...

 STACK*:PHP中級
  - 説明の仕方としては以下引用の通り
   バッファがあると、せっかく flock を使ってロックしても、書き込まれる前の
   データをディスクから読み出してしまうことがあるわけです

PHP のマニュアルによると、set_file_buffer($fp,0) は stream_set_write_buffer($fp,0) であり、『書き込み操作はバッファされなくなります』 とあります. でも 『読み込み操作がブロックされる』とは書いてありません. ちなみに、PHP5.1.2 の stream_set_write_buffer() のコードからバッファを設定している部分を 抜粋すると以下のようになっています.

// if buff is 0 then set to non-buffered
if( buf == 0 ) {
  ret = php_stream_set_option(stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
} else {
  ret = php_stream_set_option(stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_FULL, &buff);
}

これを検証するために以下のようなコードを準備してみました.

以下の結果を確認することで、『set_file_buffer() が 読み込み処理をブロックするか』ということを 確認してみたいと思います.

テスト環境/テストデータ は以下の通り.

writer1.php

 <?php
   print("writer1.start\n");
   $rfile = "rdata";
   $rlines = file($rfile)
         or die_message("$rfile isnot exist");

   $wfile = "wdata";
   $fp = @fopen( $wfile, file_exists($wfile) ? "r+": "w")
      or die_message("$wfile cannot create.");

   set_file_buffer($fp, 0);

    foreach( $rlines as $line_num => $line)
    {
      print("check\n");
      fwrite($fp,$line);
    }
   fclose($fp);
   print("writer1.end\n");
?>

writer2.php

<?php
   print("writer2.start\n");
   $rfile = "rdata";
   $contents = file_get_contents($rfile)
       or die_message("$rfile not exist");

   $wfile = "wdata";
   $fp = @fopen( $wfile, file_exists($wfile) ? "r+": "w")
       or die_message("$file cannot create.");

   set_file_buffer($fp, 0);

   fwrite($fp, $contents);
   print("writer2.write.finish\n");

   fclose($fp);
   print("writer2.end\n");
?>

reader.php

<?php
   print("reader.start\n");
   $rfile = "wdata";
   while( ! $contents = @file_get_contents($rfile) )
      ;
   print("reader: read finish.\n");

   $wfile = "wdata2";
   $fp = @fopen( $wfile, file_exists($wfile) ? "r+": "w")
      or die_message("$wfile not exist");

   print("reader.output.start\n");
   fwrite($fp,$contents);
   print("reader.output.end\n");

   fclose($fp);
   print("reader.end\n");
?>

set_file_buffer_test1.pl とその結果

#!//usr/bin/perl
unlink("wdata");
unlink("wdata2");

system("php -q writer1.php &");
# busy loop
for($i=0;$i<6000;$i++){
        ; 
}
system("php -q reader.php &");
exit;

以下のように書き込み処理の後に読み込み処理が行われることもあれば、

writer1.start
check
check
 :
check
writer1.end
reader.start
reader: read finish.
reader.output.start
reader.output.end
reader.end

読み込み処理が書き込み処理中に行われることもあります.

reader.start
writer1.start
check
reader: read finish.
check
reader.output.start
reader.output.end
reader.end
check
check
 :
check
check
writer1.end

set_file_buffer_test2.pl とその結果

#!//usr/bin/perl

unlink("wdata");
unlink("wdata2");

system("php -q writer2.php &");

# busy loop;
for($i=0;$i<6000;$i++) {
        ;
}

system("php -q reader.php &");
exit;

こちらも、以下のように書き込み処理の後に読み込み処理が行われることもあれば、

writer2.start
writer2.write.finish
writer2.end
reader.start
reader: read finish.
reader.output.start
reader.output.end
reader.end
writer2.start
reader.start
writer2.write.finish
writer2.end
reader: read finish.
reader.output.start
reader.output.end
reader.end

こちらも、以下のように書き込み処理の後に、読み込み処理が先に終わってしまうこともあります.

writer2.start
reader.start
reader: read finish.
reader.output.start
reader.output.end
reader.end
writer2.write.finish
writer2.end

最後の場合だけ申し訳ありませんが、この時のファイルサイズは以下のような状態でした.

結論.

『 set_file_buffer() は 書き込みバッファに対する処理であって、 読み込み処理をブロックすることはない. 』 と考えます.

ところで (引用が一部無くなっている?)

コメント: PHP 5.3.2以降のfclose()


*1 遅延書き込みで無いOSでは他にも遅くなる理由がありますが
*2 OSに関する書籍などの、プロセスに関する部分を参照して下さい
*3 2011-01-06 時点で、すでにPHP 5.3.5までリリース済み
*4 POSIX
*5 昔本屋で買ったPOSIX Part1 の fclose() にはそんな風な事が書いてあります

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-11-12 (水) 12:09:02
Site admin: PukiWiki Development Team

PukiWiki 1.5.2+ © 2001-2019 PukiWiki Development Team. Powered by PHP 5.6.40-0+deb8u8. HTML convert time: 0.380 sec.

OSDN