Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine

$|++ Does What, Exactly? (was: $++ Does What, Exactly?)

by Anonymous Monk
on Feb 10, 2001 at 11:16 UTC ( #57592=perlquestion: print w/replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I know that stops buffering, but where would it be useful? Does anyone have a before and after example of code w/ and w/o $|++; that display an obvious change? Its got me interested now ;)


2001-03-03 Edit by Corion : Changed title

  • Comment on $|++ Does What, Exactly? (was: $++ Does What, Exactly?)

Replies are listed 'Best First'.
Re: $++ Does What, Exactly?
by extremely (Priest) on Feb 10, 2001 at 11:36 UTC
    Are you on Unix? (not sure how WinXx reacts) Try this:
    open T1, ">>test1.out"; open T2, ">>test1.out"; foreach (0..20) { print T1 "1:$_$/"; print T2 "2:$_$/"; } close T2; #notice close order... close T1; open T1, ">>test1.out"; open T2, ">>test1.out"; select T1; $|=1; select T2; $|=1; foreach (0..20) { print T1 "3:$_$/"; print T2 "4:$_$/"; } close T2; close T1;

    The total output of the first for loop is smaller than the print buffers on most machines. You'll wind up with the lines out of order from what you'd expect because the data isn't actually written until the close flushes the buffer to disk.

    With both the filehandles set to autoflush, the lines alternate the way you would expect. The benefit to caching is that you get better disk performance. The benefit to flushing is that you get the data written immediately. That can be a big deal if you have multuple time sensitive programs writing to one log file. Imagine if a webserver left caching on while writting the log. you'd get chunks of lines in order from each httpd child and then flip back 3 seconds for the next child's data rather than a smooth temporal stream of requests. Very ugly.

    $you = new YOU;
    honk() if $you->love(perl)

      It reacts well on Windows. Why should it react weirdly under windows ?
        Well, because a lot of Perl's behavior on the IO side is dictated by the C stdio library and the OS's defaults. For all I know some Windows platforms or C libs may default autoflush to on for all handles when the program is run at console. You never really know about some of these little things and since I didn't have a WinXx box to test it on, I threw in a caveat. With the weirder aspects of any cross-platform system, you need to be certain that you aren't seeing the platform and not the system.

        Just for fun, goto Super Search and look for "Windows fork" in article bodies.

        $you = new YOU;
        honk() if $you->love(perl)

Re: $++ Does What, Exactly?
by maverick (Curate) on Feb 10, 2001 at 11:57 UTC
    If it isn't clear from the code example what's going on, here's my attempt at an explination. Unix systems (most) buffer output. In other words print "foo" doesn't happen immediately; the system holds this output in temporary memory (a buffer) until either a) the buffer is full or b) the system isn't using the disk and it's a convient time to flush (empty) the buffer. The idea is to improve disk performance.

    There are some scenarios where you want the output to not be buffered. For example, you have several processes writing to the same file and you don't want the output of one to clobber the output of another (the Apache web server is a good example).

    Try this piece of code

    for (1..10) { print "$_\r"; sleep(1); } print "\n"; $| = 1; for (1..10) { print "$_\r"; sleep(1); } print "\n";
    You should get a long pause and then all of a sudden "10". Then on the next line you should get a steady count from 1 to 10. The reason is that the 1 - 10 is in the buffer and hasn't been flushed to the screen yet. When $| becomes set to 1, the buffer flushes and you get all the output so fast that all you see is the 10. On the next one, the buffer isn't used, so you see every number as it is printed.


Re: $++ Does What, Exactly?
by tilly (Archbishop) on Feb 10, 2001 at 11:44 UTC
    On some platforms select for timeouts won't work, so you have to use sleep instead.
    $|++; for (split //, "Just a proud\b\b\b\b\b\bnother Perl hacker,\n") { print; select (undef, undef, undef, 0.3); }
    Without $|++ this would most emphatically not have the same effect. :-)

    More practically, I have seen CGIs that use system calls fail if the CGI script was buffered, and the thing called did not use buffering. But most of the time you want buffering since it is easier on the system and makes IO faster.

    Apparently by default Windows turns buffering off on interactive scripts. You may need to pipe the output of the above through the following script to see the effect of $|:

    $| = 1; while (read(STDIN, $buf, 1)) { print $buf; }
    UPDATE 2
    I have been informed that this doesn't work. I know I have gotten the principle working on NT before, but without Windows to test on, I can't really debug this one. Sorry.
      Actually, I think perl in general has begun sniffing the STDOUT to see if it is a terminal and turning buffering off if it is. My example printed to the screen with STDOUT and STRERR rather than a file was dissappointingly doing the right thing. =)

      $you = new YOU;
      honk() if $you->love(perl)

        On Linux at least the default buffering for things heading to the screen is buffered on the return. Which is why my interactive example involved sending one character at a time. :-)

        It also flushes upon reading from STDIN. These two features make interactive scripts much more reasonable.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://57592]
Approved by root
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (6)
As of 2017-09-24 09:22 GMT
Find Nodes?
    Voting Booth?
    During the recent solar eclipse, I:

    Results (273 votes). Check out past polls.