【发布时间】:2014-06-23 12:17:07
【问题描述】:
我有一个 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。我需要使用select 或poll,因为我不想锤击CPU。
请注意:我说的是标准输入,而不是标准输出。 $|++ 不是解决方案。
[编辑] 根据 cmets 和其他答案更新我的问题以澄清。
正在写入 STDOUT(在管道的另一端)的程序在每次写入后都会进行行缓冲和刷新。每次写入都包含一个换行符,因此实际上缓冲对于第一个程序的 STDOUT 来说不是问题。
为了验证这是真的,我编写了一个小型 C 程序,该程序从禁用了 STDIN 缓冲的同一程序中读取管道输入(带有 _IONBF 的 setvbuf)。输入立即出现在测试程序的 STDIN 中。可悲的是,第一个程序的输出似乎不是问题。 [/EDIT]
感谢您的任何见解!
PS。我已经做了相当多的谷歌搜索。 This link 是我找到的最接近答案的答案,但它肯定不能满足我的所有需求。
【问题讨论】:
-
如果您将示例代码更改为以通常的方式逐行读取 STDIN,则您的示例代码不会“影响 CPU”。 CPU 使用率仅在您进行非阻塞读取时才会成为一个问题,以便程序在等待数据时可以执行其他操作。也许你真正的程序正在做一些更复杂的事情。
-
Re“我不想无限调用 sysread 而不阻塞”,为什么不调用
sysread阻塞呢?sysread将始终在数据到达后立即返回。 (不会解决你的问题,但它会让你的程序变得更简单。) -
我不能使用阻塞,因为处理的其他任务未包含在粘贴的代码中(子收获等)。这让我可以选择无限循环 sysread(没有阻塞)(如果我没记错的话)将锁定 CPU。