13

有人可以告诉我如何在 Perl 中触发并忘记一个进程吗?我已经看过ruby​​: how to fire and forget a subprocess? 在 Ruby 中做同样的事情。

4

4 回答 4

21

perlfaq8如何在后台启动进程的回答?


几个模块可以启动不会阻塞您的 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&“)”的问题。

于 2010-01-25T17:12:57.460 回答
1

如果你想守护你的 Perl 脚本,我会研究Proc::Daemon。

于 2010-01-25T16:53:21.730 回答
0

好吧,您不应该使用system(),因为我了解此调用将在继续执行之前等待函数的返回。我会简单地使用 linux 并以这种方式启动该过程,但请记住,这种方式会引发 shell 的新副本,因此如果您正在寻找性能,我不会在循环中执行此操作,例如:

process_name > /dev/null 2>&1 &;

这将启动进程重定向STDOUT/dev/nullSTDERR

于 2010-01-25T16:56:06.640 回答
0

如果您希望“父”进程退出时看门狗“子”进程消失,那么您真的不希望父进程“触发并忘记”子进程。您要么需要 fork(如 brian d foy 所述),要么将父级的 PID 传递给子级(以便后者可以轮询进程表 - 不推荐)。

于 2010-01-25T22:26:06.163 回答