как отключить буферизацию перенаправления на файл в stdout в perl? - PullRequest
2 голосов
/ 01 июля 2011

Вот скрипт, который запускает 10 процессов, каждый из которых записывает 100 000 строк в свой STDOUT, который унаследован от родителя:

#!/usr/bin/env perl
# buffer.pl
use 5.10.0;
use strict;
use warnings FATAL => "all";
use autodie;

use Parallel::ForkManager;
my $pm = Parallel::ForkManager->new(4);

$|=1; # don't think this does anything with syswrite...

# start 10 jobs which write 100,000 lines each
for (1 .. 10 ) {
    $pm->start and next;

    for my $j (1 .. 100_000) {
        syswrite(\*STDOUT,"$j\n");
    }

    $pm->finish;
}
$pm->wait_all_children;

Если я передаю канал другому процессу, все в порядке ..

$ perl buffering.pl | wc -l
1000000

Но если я передаю данные на диск, syswrites забивают друг друга.

$ perl buffering.pl > tmp.txt ; wc -l tmp.txt
457584 tmp.txt

Более того, если я открываю дескрипторы файла записи в дочерних процессах и записываю напрямую в tmp.txt:

#!/usr/bin/env perl
# buffering2.pl
use 5.10.0;
use strict;
use warnings FATAL => "all";
use autodie;

use Parallel::ForkManager;
my $pm = Parallel::ForkManager->new(4);

$|=1;

for (1 .. 10) {
    $pm->start and next;
    open my $fh, '>', 'tmp.txt';

    for my $j (1 .. 100_000) {
        syswrite($fh,"$j\n");
    }
    close $fh;

    $pm->finish;
}
$pm->wait_all_children;

tmp.txt содержит 1 000 000 строк, как и ожидалось.

$ perl buffering2.pl; wc -l tmp.txt
100000 tmp.txt

Так что перенаправление через '>' на диск имеет некоторую буферизацию, а перенаправление на процесс - нет?Что за сделка?

1 Ответ

3 голосов
/ 01 июля 2011

Когда вы перенаправляете весь Perl-скрипт, вы получаете один файловый дескриптор (созданный оболочкой при выполнении > tmp.txt и унаследованный как stdout от perl), равный dup 'd каждому дочернему элементу. Когда вы явно open в каждом дочернем элементе, вы получаете различные файловые дескрипторы (не dup с оригинала). Вы должны быть в состоянии повторить случай перенаправления оболочки, если вы выведете open my $fh, '>', 'tmp.txt' из своей петли.

Случай с конвейером работает, потому что вы говорите с каналом, а не с файлом, и у него нет понятия о смещении, которое может непреднамеренно использоваться в ядре, как я описал выше.

...