这是一个启动 10 个进程的脚本,每个进程向其 STDOUT 写入 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
但是如果我通过管道传输到磁盘,系统写入就会互相破坏。
$ 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
那么通过“>”重定向到磁盘有某种缓冲,但重定向到进程则没有?这是怎么回事?
最佳答案
当你重定向整个 perl 脚本时,你会得到一个文件描述符(当你执行 > tmp.txt
时由 shell 创建并由 perl 继承为 stdout
),即 dup
送给每个 child 。当您明确 open
在每个子文件中,您都会获得不同的文件描述符(不是原始文件的 dup
)。如果您提升 open my $fh, '>', 'tmp.txt'
,您应该能够复制 shell 重定向情况。脱离你的循环。
管道情况之所以有效,是因为您正在与管道而不是文件进行通信,并且它没有偏移量的概念,正如我上面所描述的,偏移量可能会无意中在内核中共享。
关于perl - 如何在 perl 中禁用 stdout 重定向到文件缓冲?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6542199/