如何在CGI中分离线程?

时间:2012-05-09 13:22:38

标签: perl background cgi fork detach

我有一个Perl插件需要一段时间才能完成操作。该插件通常是通过Web从CGI接口启动的,该接口应该在后台发送并立即打印消息。不幸的是我找不到办法做到这一点。我的意思是CGI正确启动插件但它也等待它完成我不想发生。我尝试使用& ,使用 fork ,使用 detach ,即使使用Proc::Background,到目前为止还没有运气。我很确定这个问题与CGI有关,但我想知道为什么,如果可能的话,要解决这个问题。以下是我尝试过的代码,请记住,所有方法都可以在控制台上运行,只是CGI会产生问题。

# CGI
my $cmd = "perl myplugin.pl";

# Proc::Background
my $proc = Proc::Background->new($cmd);
# The old friend &
system("$cmd &");
# The more complicated fork
my $pid = fork;
if ($pid == 0) {
    my $launch = `$cmd`;
    exit;
}
# Detach

print "Content-type: text/html\n\n";
print "Plugin launched!";

我知道StackOverflow上有一个similar question但你可以看到它并没有解决我的问题。

2 个答案:

答案 0 :(得分:4)

这基本上是一个Perl实现的shell在pilcrow的答案中幕后做的事情。它有两个潜在的优点,它不需要使用shell来调用你的第二个脚本,并且在极少数情况下fork会失败时它会提供更好的用户反馈。

my @cmd = qw(perl myplugin.pl);

my $pid = fork;
if ($pid) {
    print "Content-type: text/html\n\n";
    print "Plugin launched!";
}
elsif (defined $pid) {
    # I skip error checking here because the expectation is that there is no one to report the error to.
    open STDIN,  '<', '/dev/null';
    open STDOUT, '>', '/dev/null'; # or point this to a log file
    open STDERR, '>&STDOUT';
    exec(@cmd);
}
else {
    print "Status: 503 Service Unavailable\n";
    print "Content-type: text/html\n\n";
    print "Plugin failed to launch!";
}

答案 1 :(得分:3)

让您的子进程关闭或删除其继承的标准输出和标准错误,以便Apache知道它可以自由响应客户端。关于这个问题,请参见merlyn的article

示例:

system("$cmd >/dev/null 2>&1 &");

虽然我不禁看到system("$cmd ...")