有人可以告诉我如何在 Perl 中触发并忘记一个进程吗?我已经看过ruby: how to fire and forget a subprocess? 在 Ruby 中做同样的事情。
4 回答
几个模块可以启动不会阻塞您的 Perl 程序的其他进程。您可以使用 IPC::Open3、Parallel::Jobs、IPC::Run 和一些 POE 模块。有关详细信息,请参阅 CPAN。
你也可以使用
system("cmd &")
或者您可以使用 perlfunc 中“fork”中记录的 fork,并在 perlipc 中提供更多示例。如果您使用的是类 Unix 系统,请注意以下几点:
STDIN、STDOUT 和 STDERR 是共享的
主进程和后台进程(“子”进程)共享相同的 STDIN、STDOUT 和 STDERR 文件句柄。如果两者都尝试同时访问它们,可能会发生奇怪的事情。您可能想为孩子关闭或重新打开这些。您可以通过“打开”管道来解决此问题(请参阅 perlfunc 中的“打开”),但在某些系统上,这意味着子进程不能比父进程存活。
信号
您必须捕获 SIGCHLD 信号,也可能捕获 SIGPIPE。当后台进程完成时发送 SIGCHLD。当您写入子进程已关闭的文件句柄时会发送 SIGPIPE(未捕获的 SIGPIPE 可能会导致您的程序静默死亡)。这不是“system("cmd&")”的问题。
僵尸
您必须准备好在子进程完成时“收获”子进程。
$SIG{CHLD} = sub { wait };
$SIG{CHLD} = 'IGNORE';
您也可以使用双叉。您立即为您的第一个孩子等待(),一旦它退出,初始化守护程序将为您的孙子等待()。
unless ($pid = fork) {
unless (fork) {
exec "what you really wanna do";
die "exec failed!";
}
exit 0;
}
waitpid($pid, 0);
有关执行此操作的其他代码示例,请参见 perlipc 中的“信号”。僵尸不是“system(”prog&“)”的问题。
如果你想守护你的 Perl 脚本,我会研究Proc::Daemon。
好吧,您不应该使用system()
,因为我了解此调用将在继续执行之前等待函数的返回。我会简单地使用 linux 并以这种方式启动该过程,但请记住,这种方式会引发 shell 的新副本,因此如果您正在寻找性能,我不会在循环中执行此操作,例如:
process_name > /dev/null 2>&1 &
;
这将启动进程重定向STDOUT
到/dev/null。STDERR
如果您希望“父”进程退出时看门狗“子”进程消失,那么您真的不希望父进程“触发并忘记”子进程。您要么需要 fork(如 brian d foy 所述),要么将父级的 PID 传递给子级(以便后者可以轮询进程表 - 不推荐)。