我只是想了解如何正确使用 open2
功能。
请参阅下面的示例。它适用于小型 $max
, 但自然地,如果我写的时间足够长到 $hIn
, 所以最终它会被阻塞,因为没有任何东西连续读取输出上的数据。
use 5.26.0;
use IPC::Open2;
my $max = 100000;
my $pid = open2(my $hOut, my $hIn, "cat") || die "failed 'cat': $!";
{
my $cnt = 0;
#When $max is big (e.g. 100000) so the code below will get blocked
#when writing to $hIn
while ($cnt<$max) {say $hIn $cnt++;}
close($hIn) || say "can't close hIn";
}
while(<$hOut>) { print; }
close($hOut) || say "can't close hOut";
waitpid( $pid, 0 );
我能想到的唯一解决方案是启动另一个将在后台进行写入的线程。
使用下面的代码我可以写入 $hIn
我想要多少数据都可以,并在主线程中读取它们,但是 $hIn
似乎没有关闭。因此 while(<$hOut>)
在等待更多输出时永远不会完成。
use 5.26.0;
use threads;
use IPC::Open2;
my $max = 100000;
my $pid = open2(my $hOut, my $hIn, "cat") || die "failed 'cat': $!";
my $thr = threads->create(sub {
my $cnt = 0;
while ($cnt<$max) {say $hIn $cnt++;}
#The close does not have any effect here (although no error is produced)
close($hIn) || say "can't close hIn";
});
#This outputs all the data written to $hIn but never leaves the loop...
while(<$hOut> ) { print; }
close($hOut) || say "can't close hOut";
$thr->join;
waitpid( $pid, 0 );
我的问题是:
- 假设我的线程方法没问题,我如何从后台线程关闭文件句柄?
- 如果不行(实际上
use threads
在 Perl 中是不鼓励的),那么有人可以提供一个 open2 的工作示例,它可以写入和读取大量数据而不会被阻塞等待读取器或写入器的风险吗?
编辑:按照您的建议,使用 IPC::Run 实现上述代码:
use 5.26.0;
use IPC::Run qw/ run /;
my $max = 1000000;
run sub {
my $cnt = 0;
while ($cnt<$max) {say $cnt++;}
},
"|", "cat",
"|", sub {
while(<> ) {
print;
}
}
or die "run sub | cat | sub failed: $?";
它运行没有缺陷,代码可读性很强......我很高兴了解了这个模块。感谢大家!
然而,我认为这个问题没有答案。如果无法使用 open2
编写此功能直接地,为什么它甚至存在并使人们感到困惑?也无法从不同的线程关闭文件句柄对我来说看起来像是一个错误(当然是 - 关闭至少应该报告一个错误)。
最佳答案
- 你的程序停止了,因为它正在写入的管道已满。
cat
的管道已满,因为cat
停止读取它。cat
停止,因为它写入的管道已满。- 来自
cat
的管道已满,因为您的程序没有从中读取数据。
所以你有两个程序在等待对方做某事。这是一个僵局。
低级别的解决方案是使用select
来监控管道的两端。
高级解决方案是让 IPC::Run或 IPC::Run3为你做那些艰苦的工作。
use IPC::Run qw( run );
my $cnt_max = 100000;
my $cnt = 0;
run [ "cat" ],
'<', sub { $cnt < $cnt_max ? $cnt++ . "\n" : undef };
关于multithreading - Perl:从后台线程关闭 open2 句柄,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54012999/