Perl Tips: バッファリングを止める
2023/12/17
出力はバッファリングされている
  • 画面(標準出力)やファイルに、例えばprint文等で出力をする際、すぐに出力されないことにお気付きでしょうか。

  • 下記のように1秒ごとに文字を画面出力及び改行(\n)する場合、狙い通り1秒毎に文字が表示されるでしょう。
  • #!perl -w
    use strict;
    
    for (my $i=1; $i<4; $i++) {
        sleep(1);
        print "$i\n";
    }
    
    >test.pl
    1
    2
    3
  • では改行ではなく復帰(行先頭への移動:\r)ならばどうでしょう。同一画面行内で数字が1,2,3...と変わっていくのが期待している表示ですが、1,2は現れず3だけが出てきたと思います。
  • #!perl -w
    use strict;
    
    for (my $i=1; $i<4; $i++) {
        sleep(1);
        print "$i\r";
    }
    
    >test.pl
    3 # 1,2は表示されない
    
  • この理由は、Perlの出力がバッファリングされているからです。画面出力は行バッファリング、改行単位での出力です。ファイル出力も4kbyteのバッファリングがあります。

バッファリングを止める
  • 例えば先のように同一行内で表示変更するために、バッファリングを止めたい(オートフラッシュ有効化したい)場合、IO::Handleautoflushメソッドを使用します。
  • #!perl -w
    use IO::Handle;
    use strict;
    
    STDOUT->autoflush(1); # STDOUT(標準出力)のautoflush有効化(引数に1設定)
    
    for (my $i=1; $i<4; $i++) {
        sleep(1);
        print "$i\r";
    }
    
    >test.pl
    3 # 1,2も表示されたと思います
  • IO::Handleautoflush()メソッドはファイルハンドルにも使えます。
  • #!perl -w
    use IO::Handle;
    use strict;
    
    my $fh;
    open($fh, "> hoge.txt") or die; # 変数にファイルハンドル紐づけ
    
        $fh->autoflush(1);    # ファイルハンドルのautoflush有効化(引数に1設定)
        
        for (my $i=1; $i<10; $i++) {
            sleep(1);
            print $fh "$i\n"; # ファイル出力(autoflush有効)
            print     "$i\n"; # 画面出力(改行付なのでautoflushに関係なく出力)
        }
    close();
    
  • 尚バッファリングを「有効」に戻したい場合、autoflushメソッドの引数に0を設定すれば良いです。

  • Perlの特殊変数$|('|'は縦線/パイプ)を使う方法もありますが、可読性が低いので紹介から省きました。
Copyright(C) 2023 Altmo
本HPについて