使用PHP生成多个进程以处理数据。
我有一个需要处理的数据队列(AmazonSQS),我想用多个进程(PHP)来处理它 我想让童工做这样的事情(psedouish代码): 我总是需要一个子进程来运行,但在需要的时候我想(fork?)一个子进程,这样它可以帮助更快地处理队列 有人能帮我大致了解一下我需要的PHP框架,或者给我指出正确的方向吗使用PHP生成多个进程以处理数据。,php,process,fork,Php,Process,Fork,我有一个需要处理的数据队列(AmazonSQS),我想用多个进程(PHP)来处理它 我想让童工做这样的事情(psedouish代码): 我总是需要一个子进程来运行,但在需要的时候我想(fork?)一个子进程,这样它可以帮助更快地处理队列 有人能帮我大致了解一下我需要的PHP框架,或者给我指出正确的方向吗 我想我需要看一看,但我不确定如何使用它来管理多个流程。当您分叉一个流程时。你复制了这个过程。换句话说,副本(fork)包含原始进程拥有的所有内容(包括文件句柄) 那么,您如何知道您是父进程还是分
我想我需要看一看,但我不确定如何使用它来管理多个流程。当您分叉一个流程时。你复制了这个过程。换句话说,副本(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_等待。如果生成多个子系统,则需要更复杂的系统
也许你不应该分岔,而应该看看exec函数的范围
警告
分叉过程可能会出现问题,当一个子进程退出时,数据库句柄会被关闭,等等。如果出现问题,您还可以使用多个进程终止服务器。花大量时间玩、测试和阅读
DC我知道这是一个旧线程,但看起来它可能需要一个更完整的答案。这就是我通常在PHP中生成多个进程的方式 一句警告的话:意思是,该语言要执行几秒钟,然后退出。尽管PHP中的垃圾清理已经走过了漫长的道路,但要小心。监视进程是否存在意外内存消耗或其他异常情况。在设置并忘记之前,要像鹰一样观察一段时间,即使如此,还是要偶尔检查一次流程,或者让他们在出现问题时自动通知 当我在打字的时候,似乎也是个好主意 当准备好运行程序时,我建议在日志上执行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);
}
}
?>
这类事情并不是PHP的本意或擅长之处。分叉过程比派生线程要昂贵得多,这是通常的做法。我可以用Python轻松地使用线程完成这项工作,尽管出于特定原因,PHP是我唯一可用的选项。Python在多线程代码方面有自己的问题,最明显的是CPython上的GIL。Jython/IronPython没有这个问题,但我想需要编译。
<?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);
}
}
?>