我有一个需要处理的数据队列(Amazon SQS),我想用多个进程(用PHP)来完成。
我希望童工做这样的事情(pseduoish代码):
while(true) {
$array = $queue->fetchNItems(10); // get 10 items
if(!count($array))
killProcess();
foreach($array as $item) {
... // process the item
$queue->remove($item);
}
sleep(2);
}
我总是需要运行一个子进程,但是在需要的时候我想(fork?)一个子进程,以便它可以帮助更快地处理队列。
有人可以帮我解决我需要的粗略的PHP骨架,还是指向正确的方向?
我想我需要看看http://php.net/manual/en/function.pcntl-fork.php,但我不确定如何使用它来管理多个流程。
答案 0 :(得分:2)
当你分叉一个进程。你复制了那个过程。换句话说,副本(fork)包含原始进程具有的所有内容(包括文件句柄)
那你怎么知道你是父母还是分叉的过程?
链接页面中的示例非常清楚地显示了
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if ($pid) {
// we are the parent
pcntl_wait($status); //Protect against Zombie children
} else {
// we are the child
}
?>
将此扩展到您想要的
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if ($pid) {
// we are the parent
pcntl_wait($status); //Protect against Zombie children
} else {
// we are the child
while(true) {
$array = $queue->fetchNItems(10); // get 10 items
if(!count($array)) {
exit();
}
foreach($array as $item) {
... // process the item
$queue->remove($item);
}
sleep(2);
}
}
?>
这将在分叉进程上创建(在此实例中浪费)使用循环来创建多个进程。当孩子完成退出后会杀死孩子的过程。并且pcntl_wait()将返回允许父级继续。我不确定php,但如果父进程死亡或退出,它将终止子进程,即使子进程没有完成。因此pcntl_wait。如果你产生多个孩子,则需要更复杂的系统。
也许而不是分叉你应该看一下exec函数的范围?
警告。
分叉过程可能会出现问题,数据库句柄会在子项退出时关闭等。如果出现问题,您还可以使用多个进程终止服务器。花很多时间玩,测试和阅读。DC
答案 1 :(得分:0)
我知道这是一个旧线程,但看起来它可以使用更完整的答案。这就是我通常在PHP中生成多个进程的方法。
谨慎之处:PHP was meant to die.意思是,语言意味着要执行几秒钟然后退出。虽然,PHP中的垃圾清理已经走了很长的路,但要小心。监视您的进程以查看意外内存消耗或其他异常情况。在设置之前观察鹰派之类的一段时间并忘记它,即便如此,仍然会偶尔检查一下这些过程,或者让它们在出现问题时自动通知。
当我打字的时候,在github上打它似乎是一个好主意。
准备运行程序时,我建议在日志上执行tail -f查看输出。
<?php
/*
* date: 27-sep-2015
* auth: robert smith
* info: run a php daemon process
* lic : MIT License (see LICENSE.txt for details)
*/
$pwd = realpath("");
$daemon = array(
"log" => $pwd."/service.log",
"errorLog" => $pwd."/service.error.log",
"pid_file" => $pwd."/",
"pid" => "",
"stdout" => NULL,
"stderr" => NULL,
"callback" => array("myProcessA", "myProcessB")
);
/*
* main (spawn new process)
*/
foreach ($daemon["callback"] as $k => &$v)
{
$pid = pcntl_fork();
if ($pid < 0)
exit("fork failed: unable to fork\n");
if ($pid == 0)
spawnChores($daemon, $v);
}
exit("fork succeeded, spawning process\n");
/*
* end main
*/
/*
* functions
*/
function spawnChores(&$daemon, &$callback)
{
// become own session
$sid = posix_setsid();
if ($sid < 0)
exit("fork failed: unable to become a session leader\n");
// set working directory as root (so files & dirs are not locked because of process)
chdir("/");
// close open parent file descriptors system STDIN, STDOUT, STDERR
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
// setup custom file descriptors
$daemon["stdout"] = fopen($daemon["log"], "ab");
$daemon["stderr"] = fopen($daemon["errorLog"], "ab");
// publish pid
$daemon["pid"] = sprintf("%d", getmypid());
file_put_contents($daemon["pid_file"].$callback.".pid", $daemon["pid"]."\n");
// publish start message to log
fprintf($daemon["stdout"], "%s daemon %s started with pid %s\n", date("Y-M-d H:i:s"), $callback, $daemon["pid"]);
call_user_func($callback, $daemon);
// publish finish message to log
fprintf($daemon["stdout"], "%s daemon %s terminated with pid %s\n", date("Y-M-d H:i:s"), $callback, $daemon["pid"]);
exit(0);
}
function myProcessA(&$daemon)
{
$run_for_seconds = 30;
for($i=0; $i<$run_for_seconds; $i++)
{
fprintf($daemon["stdout"], "Just being a process, %s, for %d more seconds\n", __FUNCTION__, $run_for_seconds - $i);
sleep(1);
}
}
function myProcessB(&$daemon)
{
$run_for_seconds = 30;
for($i=0; $i<$run_for_seconds; $i++)
{
fprintf($daemon["stdout"], "Just being a process, %s, for %d / %d seconds\n", __FUNCTION__, $i, $run_for_seconds);
sleep(1);
}
}
?>