Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

So here is my dillema...I have two scripts, the first one tails the file looking for any updates:
use strict; use warnings; use File::Tail; my $name = 'C:\File\test.dat'; my $ref=tie *FH,"File::Tail",(name=>$name, ignore_nonexistant=>1, interval=>0, maxinterval=>0.1, tail=>-1, maxbuf=>16, adjustafter=>1); while (<FH>) { print "$_"; }
and the second sits in a while loop writing data to the same file every second:
use strict; use warnings; open(WRITE, ">>C:\\File\\test.dat"); my $num = 1; while(1) { print "$num\n"; print WRITE "$num\n"; sleep 1; $num ++; } close WRITE;
I've messed with the buffer size, tried flushing the buffer via ($|++) on the print side but the script running the tail never seems to update. I'm assuming this has something to do with the file being open on both sides.
Can anyone give me some pointers?

Replies are listed 'Best First'.
Re: Tail, whiles and buffers ?
by davido (Cardinal) on Oct 19, 2006 at 17:13 UTC

    If your writing script is sleeping for one second between each iteration, there would be virtually no performance hit if you opened the file for output within the loop and closed it immediately afterward within the loop, so that it gets closed on each iteration just before sleeping. This would have the advantage of flushing the buffer on each iteration.

    You should also implement flocking at both ends; flock your writes, and do a shared flock on your reads. There's no good reason that I can think of not to, given the examples you've posted.

    Update:
    An aside... Corion pointed out that on Win32 flock is unnecessary. So that part of the advice won't improve your situation if you're on Win32, but it won't hurt either other than adding a little code, and if the code may be executed in other OS's, it'll probably help.

    At any rate, opening and closing the file within the loop should help.


    Dave

      I think I found the answer...I was using a deprecated version of auto flush I guess. This seems to work:
      use IO::Handle; open(WRITE, ">>C:\\File\\test.dat"); WRITE->autoflush(1);

        That's strange, your original post said nothing about using IO::Handle. So your example code was irrelevant. Nice.


        Dave

      If I remove the sleep from my while loop you can see my issue. The tail script always seems to be several hundred lines behind.

        Yes, but in your example code there was a sleep in the loop. Is that not relevant?


        Dave

      That does work, unfortunately my "real" script is waiting for output from a module that is using a foreach loop that could potentially contain thousands of elements, and I need to be able to detect them as soon as they get written.

        Maybe writing to a file and reading from the file at the same time isn't the most efficient means of communication between the two scripts. It's possible to write to a logfile, and also open a pipe between two processes. With IO::Tee you could write to both filehandles simultaneously.


        Dave