【问题标题】:How do I do a non-blocking read from a pipe in Perl?如何在 Perl 中从管道中进行非阻塞读取?
【发布时间】:2011-04-15 23:45:30
【问题描述】:

我有一个程序正在调用另一个程序并处理孩子的输出,即:

my $pid = open($handle, "$commandPath $options |");

现在我尝试了几种不同的方法来读取句柄而不阻塞,但几乎没有成功。

我找到了相关问题:

但是他们遇到了问题:

  • ioctl perl 经常崩溃
  • sysread 0 字节上的块(很常见)

我不确定如何解决这个问题。

【问题讨论】:

  • 查看this answer -- 使用select() 确定是否有任何数据可供读取。
  • @Ether 选择不适用于 Windows 上的文件句柄

标签: windows perl asynchronous pipe


【解决方案1】:

管道在 Windows 上的功能不如在 Unix-y 系统上。您不能在它们上使用 4 参数 select,默认容量很小。

您最好尝试基于套接字或文件的解决方法。

$pid = fork();
if (defined($pid) && $pid == 0) {
    exit system("$commandPath $options > $someTemporaryFile");
}
open($handle, "<$someTemporaryFile");

现在你要处理更多的蠕虫——定期运行waitpid 以检查后台进程何时停止创建输出,在读取$handle 后调用seek $handle,0,1 以清除eof 条件,清理临时文件,但它可以工作。

我已经编写了Forks::Super 模块来处理这样的问题(以及许多其他问题)。对于这个问题,你会像这样使用它

use Forks::Super;
my $pid = fork { cmd => "$commandPath $options", child_fh => "out" };
my $job = Forks::Super::Job::get($pid);
while (!$job->is_complete) {
    @someInputToProcess = $job->read_stdout();
    ... process input ...
    ... optional sleep here so you don't consume CPU waiting for input ...
}
waitpid $pid, 0;
@theLastInputToProcess = $job->read_stdout();

【讨论】:

  • @mobrule 我的理解是我不能在文件句柄上使用 select,所以这只是重现了我目前遇到的同样问题。
  • 您不需要在文件句柄上使用 select。读取耗尽的文件句柄将返回 undef 而不会阻塞,然后您可以调用 seek HANDLE,0,1 清除 eof 条件并再次读取。
  • @mob 那么我是否必须寻求我已经阅读了多远?还是这样处理?
  • @tzenes,不,如果seek 的第三个参数是1,则表示“相对于当前位置”寻找。如果第二个参数为零,它对光标位置没有任何影响,它只是具有清除句柄上的 eof 和错误条件的理想副作用。
  • @tzense - 参见perldoc -f seek,尤其是如何模拟“tail -f”的示例
猜你喜欢
  • 2015-01-25
  • 2020-10-27
  • 2016-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多