天天看点

PHP之多进程

来源:http://blog.sina.com.cn/s/blog_65e2f28901016q9z.html

本来没想过对进程之类的东西进行研究,但是最近遇到了一个问题,就是在公司的网站中,有时候会需要进行大数据量的运算,例如进行10万以上的用户批量关注。或者对一个不断增长的数据表数据,进行大批量的处理。

   按照以前的想法,那就是一条一条的进行处理呗,反正计算机运算的速度,应该是比较快的吧。实际的运算速度确不那么理想。尤其是针对数据库或者平台接口的读写操作时,大数据量的读写都还是比较慢的。就找了找一些多线程或者多进程处理的资料。一个程序处理是挺慢的,但是数据库和平台接口一般来说都是支持多线程并发操作的。那就Google吧。

   PHP本身是没有多线程的概念。但是PHP自身带有pcntl_fork函数,PHP手册是这样来说明此函数的:Thepcntl_fork() functioncreates a child process that differs from the parent process onlyin its PID and PPID. Please see your system's fork(2) man page forspecific details as to how fork works on your system.当成功时,返回子进程的pid,失败返回-1,但前进程为子进程时,返回0。由于函数本身依赖于操作系统的fork来实现,所以此函数只能在linux或者Unix操作系统下使用,windows操作系统下的服务器是不成功的。

   一般的起子进程的写法是:

<?php

$pid = pcntl_fork();

if($pid == -1){

        //创建失败

        die('could not fork');

}

else{

        if($pid){

                //从这里开始写的代码是父进程的

             exit("parent!");

        }

        else{

                //子进程代码,为防止不停的启用子进程造成系统资源被耗尽的情况,一般子进程代码运行完成后,加入exit来确保子进程正常退出。

                exit("child");

        }

}

?>

   上边的代码如果创建子进程成功的话,系统就有了2个进程,一个为父进程,一个为子进程,子进程的id号为$pid。在系统运行到$pid =pcntl_fork();时,在这个地方进行分支,父子进程各自开始运行各自的程序代码。代码的运行结果是parent和child,很奇怪吧,为什么一个if和else互斥的代码中,都输出了结果?其实是像上边所说的,代码在pcntl_fork时,一个父进程运行parent,一个子进程运行了child。在代码结果上就显示了parent和child。至于谁先谁后的问题,这得要看系统资源的分配了。

   如果需要起多个进程来处理数据,可以根据数据的数量,按照约定好的数量比如说1000条一个进程来起子进程。使用for循环就可以了。

   #如果获得的总数小于或等于0,等待60秒,并退出

    if ($count<= 0) 

    {

       sleep(60);

       exit;

    }

   #如果大于1000,计算需要起的进程数

    if ($count> 1000)

    {

       $cycleSize = ceil($count/1000);

    }

    else

    {

       $cycleSize = 1;

    }

    for ($i=0;$i<$cycleSize; $i++)

    {

       $pid    =pcntl_fork();

       if($pid == -1)

       {

           break;

       }

       else

       {

           if($pid)

           {

               #父进程获得子进程的pid,存入数组

               $pidArr[] = $pid;

           }

           else

           {

               //开始发送,子进程执行完自己的任务后,退出。

                   exit;

           }

       }

    }

   while(count($pidArr) > 0)

    {

       $myId   = pcntl_waitpid(-1,$status, WNOHANG);

       foreach($pidArr as $key => $pid)

       {

           if($myId == $pid) unset($pidArr[$key]);

       }

    }

   然后使用crontab,来使此PHP程序每隔一段时间自动执行。

   当然,示例代码比较简单,具体还需要考虑怎么防止多个子进程执行到同一条数据或者当前进程处理数据未完成时,crontab又开始执行PHP文件启用新的进程等等。

php