【问题标题】:Spawning multiple processes with PHP to process data.使用 PHP 生成多个进程来处理数据。
【发布时间】:2011-01-02 07:08:22
【问题描述】:

我有一个需要处理的数据队列 (Amazon SQS),我想用多个进程来处理(在 PHP 中)。

我希望童工做这样的事情(伪代码):

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); }

我总是需要 1 个子进程来运行,但在需要时我想(分叉?)一个子进程,以便它可以帮助更快地处理队列。

有人可以帮助我大致了解我需要什么的 PHP 框架,或者为我指明正确的方向吗?

我想我需要看看http://php.net/manual/en/function.pcntl-fork.php,但我不确定如何使用它来管理多个进程。

【问题讨论】:

  • 这种事情并不是 PHP 的真正意图或擅长的。分叉进程比生成线程要昂贵得多,这通常是这样做的。
  • 我可以很容易地在 Python 中使用线程来做这件事,尽管出于特定原因 PHP 是我唯一可用的选项。
  • Python 在多线程代码方面有自己的问题,尤其是 CPython 上的 GIL。 Jython/IronPython 没有这个问题,但我想需要编译。

标签: php process fork


【解决方案1】:

当你分叉一个进程时。您复制该过程。换句话说,副本(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 函数的范围而不是分叉?

一个警告。

分叉进程可能会出现问题,当孩子退出时数据库句柄被关闭等。如果出现问题,您还可以杀死具有多个进程的服务器。花很多时间玩、测试和阅读。

直流

【讨论】:

    【解决方案2】:

    我知道这是一个旧线程,但看起来它可以使用更完整的答案。这就是我通常在 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);
        }
      }
    ?>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多