首先,我知道这个问题(或密切的变化)已被问过一千次。我真的花了几个小时看着明显的和不那么明显的地方,但可能有一些我想念的东西。
让我更清楚地定义问题:我正在编写一个新闻通讯应用程序,我希望实际的发送过程是异步的。在用户单击“发送”时,请求立即返回,然后他们可以检查特定页面中的进度(例如,通过AJAX)。它是用传统的LAMP堆栈编写的。
在我正在使用的特定主机中,出于安全原因禁用了PHP的exec()和system(),但Perl的系统函数(exec,system和backticks)却没有。所以我的 workaround 解决方案是在Perl中创建一个“触发器”脚本,通过PHP CLI调用实际的发送者,并重定向到进度页面。
发件人的电话就行了,截至目前:
system("php -q sender.php &");
问题在于,它不会立即返回,而是等待脚本完成。我希望它在后台运行并让系统调用自己立即返回。我也试过在我的Linux终端上运行一个类似的脚本,实际上直到脚本完成后才会显示提示,即使我的测试输出没有运行,表明它确实在后台运行。
为了确保我没有遗漏任何明显的东西,我创建了一个sleepper.php脚本,它在退出之前只睡了五秒钟。还有一个像这样的test.cgi脚本,逐字:
#!/usr/local/bin/perl
system("php sleeper.php &");
print "Content-type: text/html\n\ndone";
答案 0 :(得分:9)
基本上你需要'守护'一个进程 - 分叉一个子进程,然后将它与父进程完全断开,这样父进程就可以安全终止而不会影响子进程。
您可以使用CPAN模块Proc::Daemon轻松完成此操作:
use Proc::Daemon;
# do everything you need to do before forking the child...
# make into daemon; closes all open fds
Proc::Daemon::Init();
答案 1 :(得分:7)
有时STDERR和STDOUT也可以锁定系统......为了得到这两者,我使用(对于我使用的大多数shell环境(bash,csh等)):
system("php sender.php > /dev/null 2>&1 &");
答案 2 :(得分:6)
使用fork()
,然后在子进程中调用system
。
my $pid = fork();
if (defined $pid && $pid == 0) {
# child
system($command); # or exec($command)
exit 0;
}
# parent
# ... continue ...
答案 3 :(得分:1)
另一种选择是设置gearman服务器和进行电子邮件发送的工作进程(或进程)。这样您可以控制同时发送多少电子邮件,并且不需要分叉。客户端(您的程序)可以向齿轮箱服务器添加任务(在后台,无需等待结果,如果需要),并且作业将排队,直到服务器将作业传递给可用工作人员。有齿轮手的perl和php API,所以非常方便。
答案 4 :(得分:0)
管理解决问题。显然,让它无法返回的原因是,以这种方式调用发送方并没有断开stdout。因此,解决方案只是将系统调用更改为:
system("php sender.php > /dev/null &");
感谢大家的帮助。事实上,正是在阅读关于“守护”一个过程的整个故事时,我想到了断开标准输出的想法。