我正在查看AnyEvent::Fork
模块。我有20个外部脚本我想并行调用(一次6个),并在完成后总结它们的输出。我无法实现这一点。
模块中的示例代码(仅调用1个子代码)存在问题。我只是在代码中添加一个简单的睡眠,不立即返回,父节点立即退出而不等待子进程。
open my $output, ">/tmp/log" or die "$!";
AnyEvent::Fork
->new
->eval ('
# compile a helper function for later use
sub run {
my ($fh, $output, @cmd) = @_;
# perl will clear close-on-exec on STDOUT/STDERR
open STDOUT, ">&", $output or die;
open STDERR, ">&", $fh or die;
### Added by me to demonstrate that
### $cv->recv returns immediately.
sleep 5;
exec @cmd;
}
')
->send_fh ($output)
->send_arg ("/bin/echo", "hi")
->run ("run", my $cv = AE::cv);
my $stderr = $cv->recv;
结果是/tmp/log
为空。
我不明白这里使用condvar
的方式,它不在文档中。我可以使用condvar
获取正在运行的孩子的数量吗?
请帮助如何做到这一点。
更新这里的主要问题是父母不会等待孩子完成。
答案 0 :(得分:4)
这里的问题是父和子是独立的进程,并且可以彼此独立地运行,因此如果一个人应该等待另一个,则需要显式同步。有很多方法可以做到,最简单的方法是使用AnyEvent :: Fork :: RPC,然后发送一个" wait"向孩子提出的请求,在孩子完成时会回答。
要使用裸AnyEvent :: Fork,最简单的方法是利用 - > run:
提供的bidrectional管道 AnyEvent::Fork
->new
->run (sub {
my ($fh) = @_;
sysread $fh, my $dummy, 1; # will wait for data, or eof
... done, you can now call e.g. $cv->send
sysread会尝试从孩子那里读取。如果孩子从不发送任何东西,这将阻止父母,直到孩子退出,因为在那一刻,孩子将关闭它的管道末端并且sysread获得EOF。
当然,在AnyEvent程序中你可能不想阻止,所以你使用I / O观察器:
->run (sub {
my ($fh) = @_;
my $rw; $rw = AE::io $fh, 0, sub {
... read data received, or EOF
undef $rw;
... done, you can now call e.g. $cv->send;
}
});
这个技巧也可以用于外部命令(在你的例子中是exec),通过清除子进程中管道的close-on-exec状态,然后将其传递给exec的ed程序 - 在此例如,当所有继承管道出口的程序时,管道将发出EOF信号。
这应该让你开始。还有其他方法可以做到这一点,但大多数甚至所有好的方法都会涉及一些管道进行通信,而最简单的方法就是使用AnyEvent :: Fork提供的管道。