Php在Linux下实现多进程

 一般有两种方法,一种是使用PHP自带的pcntl_*函数(仅限linux),另一种就是使用popen/proc_open,然后在php内部控制进程数量。

使用pcntl_*函数

PHP提供了一系列的pcntl_*函数,顾名思义就是process control functions,专门用来管理进程的。最常用的就是pcntl_forkpcntl_wait

pcntl_fork的作用就是从当前的进程再派生出一个子进程。pcntl_wait的作用是挂起当前进程,直到一个子进程中止。 

  
  
  
  
  1. <?php 
  2. //配合pcntl_signal使用 
  3. declare(ticks=1); 
  4. //最大的子进程数量 
  5. $max = 5; 
  6. //当前的子进程数量 
  7. $child = 0; 
  8. //当子进程退出时,会触发该函数 

  9. function sig_handler($sig) { 
  10.     global $child
  11.     switch($sig) { 
  12.         case SIGCHLD: 
  13.             echo 'SIGCHLD received'."\n"
  14.             $child--; 
  15.     } 

  16. //注册子进程退出时调用的函数 
  17. pcntl_signal(SIGCHLD, "sig_handler"); 

  18. while(true) { 
  19.     $child++; 
  20.     /** 
  21.     * 这个函数会返回两个值,一个为0,表示子进程;一个为正整数表示子进程的id 
  22.     * 所以if和else里的两段代码都会执行 
  23.     * if里的代码是父进程执行的 
  24.     * else里的代码是子进程执行的 
  25.     */ 
  26.     $pid = pcntl_fork(); 
  27.     if ($pid) { 
  28.         //这里是父进程执行的代码 
  29.         //如果子进程数超过了最大值,则挂起父进程 
  30.         //也就是说while语句不会继续执行 
  31.         if ($child >= $max) { 
  32.             pcntl_wait($status); 
  33.         } 
  34.     } 
  35.     else { 
  36.         //这里是子进程执行的代码 
  37.         //如果要执行其他命令的话,使用pcntl_exec 
  38.         echo "starting new child | now we have$child child process\n"
  39.         sleep(rand(3, 5)); 
  40.         exit
  41.     } 

上面这段代码就是保证有5个子进程一直在干活,如果$child数量大于$max,就等子进程结束后再继续运行。子进程结束后会调用 sig_handler函数,sig_handler会将$child数量减1,那边while继续执行。

使用popen/proc_open

popen会创建一个管道来连接该进程,然后使用fread/fgets/stream_get_contents来读取该进程返回的结果。跟 execsystem之类的函数不同的是,exec会等待命令执行完成,再运行下面的代码,但popen不会。proc_open又更加强大一些,支持 stdinstdout,路径设置等等。

因为这些函数只负责创建,没有相应的管理方法,所以只能在PHP文件内部自己来实现。
demo(
引用自张宴——PHP多进程并发控制的测试用例

 

  
  
  
  
  1. <?php 
  2. function run($input
  3.     global $p_number
  4.     if ($p_number <= 0) 
  5.     { 
  6.         $p_number = worker_processes($p_number); 
  7.     } 
  8.     $p_number = $p_number - 1; 
  9.     $out = popen("/bin/sh /opt/zhangyan.sh\"{$input}\" &""r"); 
  10.     pclose($out); 
  11.   
  12. function worker_processes($p_number
  13.     $limit = 500;//允许推到后台的最大进程数 
  14.     while ($p_number <= 0) 
  15.     { 
  16.         $cmd = popen("ps -ef | grep\"/opt/zhangyan.sh\" | grep -v grep | wc -l""r"); 
  17.         $line = fread($cmd, 512); 
  18.         pclose($cmd); 
  19.         $p_number = $limit - $line
  20.         if ($p_number <= 0) 
  21.         { 
  22.             sleep(1);//暂停1秒钟 
  23.         } 
  24.     } 
  25.     return $p_number
  26. $input = "http://blog.s135.com"; //模拟从队列文件中读取到的数据 
  27. for ($i = 1; $i <= 1000; $i++) 
  28.     run($input); 
  29.     echo "Idle process number: " . $p_number . "\n"
  30. ?> 

程序的逻辑:

1. 设置/opt/zhangyan.php最多允许生成500个子进程;

2. /opt/zhangyan.php读取到一条数据后,将允许生成的子进程数减1(空闲进程数$p_number=500-1=499),然后将数据交 /opt/zhangyan.sh去后台处理,不等待/opt/zhangyan.sh处理结束,继续读取下一条数据;

3. 当允许生成的子进程数减至0时(空闲进程数$p_number=0),/opt/zhangyan.php会等待1秒钟,然后检查后台还有多少个/opt /zhangyan.sh子进程尚未处理结束;

4. 如果1秒钟之后/opt/zhangyan.php发现后台的/opt /zhangyan.sh子进程数还是500(空闲进程数$p_number=0),会继续等待1秒钟,如此反复;

5. 如果/opt /zhangyan.php发现后台尚未处理结束的/opt/zhangyan.sh子进程数减少到300个了(空闲进程 $p_number=500-300=200),那么/opt/zhangyan.php会再往后台推送200/opt/zhangyan.sh子进 程;

总体来说还是使用pcntl_*系函数更方便一些,逻辑也更清楚。

你可能感兴趣的:(多线程,linux,PHP,多进程,休闲)