使用PHP生成多个进程以处理数据。

使用PHP生成多个进程以处理数据。,php,process,fork,Php,Process,Fork,我有一个需要处理的数据队列(AmazonSQS),我想用多个进程(PHP)来处理它 我想让童工做这样的事情(psedouish代码): 我总是需要一个子进程来运行,但在需要的时候我想(fork?)一个子进程,这样它可以帮助更快地处理队列 有人能帮我大致了解一下我需要的PHP框架,或者给我指出正确的方向吗 我想我需要看一看,但我不确定如何使用它来管理多个流程。当您分叉一个流程时。你复制了这个过程。换句话说,副本(fork)包含原始进程拥有的所有内容(包括文件句柄) 那么,您如何知道您是父进程还是分

我有一个需要处理的数据队列(AmazonSQS),我想用多个进程(PHP)来处理它

我想让童工做这样的事情(psedouish代码):

我总是需要一个子进程来运行,但在需要的时候我想(fork?)一个子进程,这样它可以帮助更快地处理队列

有人能帮我大致了解一下我需要的PHP框架,或者给我指出正确的方向吗


我想我需要看一看,但我不确定如何使用它来管理多个流程。

当您分叉一个流程时。你复制了这个过程。换句话说,副本(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);
    }
  }
?>