Perl STDIN没有缓冲或行缓冲

时间:2014-05-06 18:28:55

标签: perl io stdin buffering

我有一个Perl脚本,它接收来自另一个程序的输入。它使用8k(Ubuntu默认值)输入缓冲区进行缓冲,这会导致问题。我想使用行缓冲或完全禁用缓冲。它看起来不像是一个很好的方法。有什么建议吗?

use IO::Handle;
use IO::Poll qw[ POLLIN POLLHUP POLLERR ];
use Text::CSV;

my $stdin = new IO::Handle;
$stdin->fdopen(fileno(STDIN), 'r');
$stdin->setbuf(undef);

my $poll = IO::Poll->new() or die "cannot create IO::Poll object";
$poll->mask($stdin => POLLIN);

STDIN->blocking(0);

my $halt = 0;
for(;;) {
    $poll->poll($config{poll_timout}); 

    for my $handle ($poll->handles(POLLIN | POLLHUP | POLLERR)) {
        next unless($handle eq $stdin);

        if(eof) {
            $halt = 1;
            last;
        }

        my @row = $csv->getline($stdin);
        # Do more stuff here
    }

    last if($halt);
}

轮询STDIN会引发一些问题,因为IO :: Poll使用缓冲和sysread这样的直接调用(并且它们不能混合)。我不想在没有阻塞的情况下无限地调用sysread。我需要使用selectpoll,因为我不想锤击CPU。

请注意:我说的是STDIN,而不是STDOUT。 $ | ++不是解决方案。

[编辑] 根据评论和其他答案更新我的问题以澄清。

写入STDOUT的程序(在管道的另一端)是每次写入后进行行缓冲和刷新的程序。每个写入都包含一个换行符,因此实际上,缓冲不是第一个程序的STDOUT的问题。

为了验证这是真的,我写了一个小的C程序,它读取来自同一程序的管道输入,禁用STDIN缓冲(带有_IONBF的setvbuf)。输入立即出现在测试程序的STDIN中。遗憾的是,它似乎不是第一个程序输出的问题。 的 [/编辑]

感谢您的任何见解!

PS。我做了相当多的谷歌搜索。 This link是我找到答案的最接近的,但它肯定不能满足我的所有需求。

2 个答案:

答案 0 :(得分:3)

您实际上是在谈论其他程序的STDOUT 。其他程序中的解决方案是$|=1;(或等效的)。

如果你不能,你可以通过将其STDOUT连接到伪tty而不是管道(例如Expect.pm)来说服其他程序使用行缓冲而不是块缓冲。

unix程序expect有一个名为unbuffer的工具,它就是这样做的。 (它是Ubuntu上expect-dev包的一部分。)只需在命令名前加上unbuffer

答案 1 :(得分:2)

假设管道缓冲区中有两条短线。

IO :: Poll通知您要读取的数据,您可以使用readline继续(间接)读取数据。

从文件句柄一次读取一个字符是非常低效的。因此,readline(又名<>)一次从文件句柄中读取一个数据块。这两行最终在一个缓冲区中,并返回两行中的第一行。

然后等待IO :: Poll通知您有更多数据。它不了解Perl的缓冲区;它只知道管道是空的。因此,它会阻止。

This post演示了这个问题。它使用IO :: Select,但原理(和解决方案)是相同的。