如何在perl中禁用stdout重定向到文件缓冲?

时间:2011-06-30 23:31:26

标签: perl bash redirect buffering

这是一个启动10个进程的脚本,每个进程向其STDOUT写入100,000行,该行继承自父进程:

#!/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 个答案:

答案 0 :(得分:3)

当你重定向整个perl脚本时,你得到一个文件描述符(当你执行> tmp.txt时由shell创建并由perl继承为stdout),每个文件描述符为dup儿童。当您在每个子项中明确open时,您将获得不同的文件描述符(而不是原始文件的dup)。如果你将open my $fh, '>', 'tmp.txt'提升出循环,你应该能够复制shell重定向案例。

管道工作正常,因为您正在与管道而不是文件进行通信,而且它没有偏移的概念,如上所述,它可能会无意中在内核中共享。