首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在这个php子进程分叉和等待的测试示例中遗漏了什么?

在这个php子进程分叉和等待的测试示例中遗漏了什么?
EN

Stack Overflow用户
提问于 2011-06-07 20:01:06
回答 1查看 871关注 0票数 1

这只是一个测试脚本。在生成一个简单的lib之前,我正在测试基本的子叉功能,以便生成多个进程,在php中并行处理数据批处理。在继续之前,我还需要测试些什么来理解吗?据我所知,所有资源都是在分叉期间复制的,因此初始化/打开叉子之后所需的任何资源。

代码语言:javascript
复制
<?php

$childcount = 10;

for($i = 1; $i <= $childcount; $i ++)
{
    $pid = pcntl_fork();
    if ($pid == -1) {
         echo "failed to fork on loop $i of forking\n";
    } else if ($pid) {
         // we are the parent
$pidArray[$pid] = $pid;
         // and we want to wait on all children at the end of the loop
    } else {
         // we are the child
        echo "Child is outputting it's count and dying. Count: $i \n ";
        doMessage($i);
        die;
    }
}

echo "sleeping to see if child finished events queue\n";
sleep(10);

print_r($pidArray);

for($j = 1; $j <= $childcount; $j++)
{
    echo "parent is waiting on child\n";
    $pid = pcntl_wait($status); //Wait for random child to finish
    $pidArray[$pid] = "terminated";
    echo "parent found $j of the finished children\n";
}

print_r($pidArray);

function doMessage($location)
{
    sleep (rand(4,20));
    echo "outputting concurrently : $location \n"; 
}

输出如下:

代码语言:javascript
复制
me@myhost:~/$]: php test.php
sleeping to see if child finished events queue
Child is outputting it's count and dying. Count: 3 
 Child is outputting it's count and dying. Count: 4 
 Child is outputting it's count and dying. Count: 5 
 Child is outputting it's count and dying. Count: 6 
 Child is outputting it's count and dying. Count: 8 
 Child is outputting it's count and dying. Count: 9 
 Child is outputting it's count and dying. Count: 10 
 Child is outputting it's count and dying. Count: 7 
 Child is outputting it's count and dying. Count: 2 
 Child is outputting it's count and dying. Count: 1 
 outputting concurrently : 9 
outputting concurrently : 1 
outputting concurrently : 6 
Array
(
    [22700] => 22700
    [22701] => 22701
    [22702] => 22702
    [22703] => 22703
    [22704] => 22704
    [22705] => 22705
    [22706] => 22706
    [22707] => 22707
    [22708] => 22708
    [22709] => 22709
)
parent is waiting on child
parent found 1 of the finished children
parent is waiting on child
parent found 2 of the finished children
parent is waiting on child
parent found 3 of the finished children
parent is waiting on child
outputting concurrently : 5 
parent found 4 of the finished children
parent is waiting on child
outputting concurrently : 2 
parent found 5 of the finished children
parent is waiting on child
outputting concurrently : 3 
parent found 6 of the finished children
parent is waiting on child
outputting concurrently : 8 
parent found 7 of the finished children
parent is waiting on child
outputting concurrently : 7 
parent found 8 of the finished children
parent is waiting on child
outputting concurrently : 4 
outputting concurrently : 10 
parent found 9 of the finished children
parent is waiting on child
parent found 10 of the finished children
Array
(
    [22700] => terminated
    [22701] => terminated
    [22702] => terminated
    [22703] => terminated
    [22704] => terminated
    [22705] => terminated
    [22706] => terminated
    [22707] => terminated
    [22708] => terminated
    [22709] => terminated
)

我还确认了额外的pctl_wait将立即返回pid值为-1。

EN

回答 1

Stack Overflow用户

发布于 2011-06-07 20:16:58

您的示例没有触及您可以使用pcntl_fork进行封装的问题。

请记住,fork()会复制程序,这意味着所有描述符都会被复制。不幸的是,对于PHP程序来说,这是一个相当糟糕的情况,因为大多数描述符都是由PHP或PHP扩展在内部处理的。

解决这个问题的简单而且可能是“适当”的方法是手前分叉,实际上不需要在程序之间的许多不同点进行分叉,您可以简单地分叉,然后委托工作。使用主/工层次结构。

例如,如果您需要有许多使用MySQL连接的进程,那么在建立连接之前就需要分叉,这样每个子节点都有它自己和它单独管理的mysql连接。

另一件需要注意的事情是,当一个子进程死亡时。死亡应该由父母来处理。如果不是,那么子进程就会变成僵尸:它不消耗资源,但它仍然是一个带有PID的进程。这是不可取的,因为大部分(全部?)操作系统对它能够处理的进程有一个上限。

当一个孩子死后,一个信号被发送给父(SIGCHLD)。然后,父级可以处理子节点的死亡,以进行内部处理。正确的方法是使用pcntl_waitpid()来解除孩子的僵尸。您可以使用该函数来等待孩子死亡,或者检测一个孩子已经死了。当您想要对无数个孩子执行此操作时,请使用pcntl_wait()。查看PHP手册的相关部分以获得更多选项(包括让函数知道不挂起正常操作)。

然而,使用SIGCHLD并不总是万无一失的。当您快速创建许多短命子程序时,结合pcntl_waitpid()处理SIGCHLD可能不会处理所有僵尸进程。

希望这能帮上忙,php.net上的文档没问题,但在我看来,这些功能很容易被误用,所以在主题和潜在的陷阱方面可能会更深入。

下面是一个简单的示例(从php.net注释中提取),它显示了将资源分配给父线程的错误:

代码语言:javascript
复制
<?php 
mysql_connect(/* enter a working server here maybe? */); 
$f=pcntl_fork();

while(true){    
    sleep(rand(0,10)/100); 
    $r=mysql_query("select $f;"); 

    if(!$r)die($f.": ".mysql_error()."\n"); 
      list($x)=mysql_fetch_array($r); 
      echo ($f)?".":"-"; 
    if($x!=$f) echo ($f.": fail: $x!=$f\n "); 
} 
?>

在cli上运行这个将超过不同的结果:

  • 经常只是挂起,不再输出任何东西了--
  • 也经常关闭连接,可能是因为它接收到无法处理的交错请求。
  • 有时一个进程会得到其他进程的查询结果!(因为两人都通过同一个套接字发送查询,得到答复的是纯粹的运气)

希望在扩展示例以获取数据和/或使用重新源时,这会有所帮助。

祝你快乐!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6270930

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档