我可以有一个从浏览器启动的 Perl 脚本,派生它自己,而不是等待 child 结束吗?

Can I have a Perl script, initiated from a browser, fork itself, and not wait for the child to end?

还有 posted PerlMonks。

我的 linux 服务器上有这个非常简单的 Perl 脚本。

我希望能够从另一台机器上的浏览器调用脚本
让脚本启动一个分支
让 parent 发送一个 httpResponse(释放浏览器)
马上结束parent
让 child 完成它的工作,繁重的复杂数据库工作,这可能需要一两分钟
让 child 结束自己,没有任何输出

当我从浏览器调用此脚本时,浏览器在 child 完成之前不会收到发送的响应。

是的,从命令行调用时有效。

我想做的事可行吗? p.s。我什至用 ProcSimple 试过了,但我还是挂断了。

#!/usr/bin/perl
local $SIG{CHLD} = "IGNORE";
use lib '/var/www/cgi-bin';
use CGI;

my $q = new CGI;

if(!defined($pid = fork())) {
   die "Cannot fork a child: $!";
} elsif ($pid == 0) {
   print $q->header();
   print "i am the child\n";
   sleep(10);
   print "child is done\n";
   exit;
} else {
    print $q->header();
    print "I am the parent\n";
       print "parent is done\n";
   exit 0;
}
exit 0;

一般来说,您必须 detach 父进程中的子进程才能让父进程干净地退出——否则父进程无法假定它不需要处理更多 input/output .

} elsif ($pid == 0) {
   close STDIN;
   close STDERR;
   close STDOUT;   # or redirect
   do_long_running_task();
   exit;

在您的示例中,子进程正在执行 print 语句,直到它退出。如果父进程已被终止并关闭其 I/O 句柄,这些打印会去哪里?

parent 进程启动另一个将自行运行的进程的一种方法是“双叉”。 child本身fork后马上退出,所以它的child被init接管了,不可能是僵尸

这可能对这里有所帮助,因为它似乎确实存在阻塞,因为文件描述符在 parent 和 child 之间共享,如评论中所述。如果 child 快速退出,这可能会起作用,但因为您需要一个长时间的 运行 作业的过程,那么 fork 两次

use warnings;
use strict;
use feature 'say';

my $pid = fork // die "Can't fork: $!";

if ($pid == 0) { 
    say "\tChild. Fork";

    my $ch_pid = fork // die "Can't fork from child: $!";

    if ($ch_pid == 0) {
        # grandchild, run the long job
        sleep 10; 
        say "\t\tgrandkid done";
        exit;
    }   

    say "\tChild, which just forked, exiting right away.";
    exit;
}

say "Parent, and done";

我不确定如何模拟你的设置来测试这是否有帮助,但既然你说 child 产生“无任何输出”,它可能就足够了.它应该值得一试,因为它比 demonizing 过程(我希望能达到目的)更简单。

与@mob 的 post 类似,以下是我的网络应用程序的工作方式:

    # fork long task
    if (my $pid = fork) {
        # parent: return with http response to web client
    } else {
        # child: suppress further IO to ensure termination of http connection to client
        open STDOUT, '>', "/dev/null";
        open STDIN, '>', "/dev/null";
        open STDERR, '>', "/dev/null";
    }

    # Child carries on from here, 

有时,(子)长进程会打印到一个信号量或状态文件,Web 客户端可能会查看该长进程何时完成。

我不记得几年前是哪个 Perl 专家建议的,但它在许多情况下都可靠地提供服务,并且从“re-visit 几年后 - 我在做什么?”中看起来非常清楚。透视...

请注意,如果 /dev/null 在 UNIX/Linux 之外不起作用,那么 @mob 对 close 的使用可能更普遍。