zoukankan      html  css  js  c++  java
  • 尝试php命令行脚本多进程并发执行

    php不支持多线程,但是我们可以把问题转换成“多进程”来解决。由于php中的pcntl_fork只有unix平台才可以使用,所以本文尝试使用popen来替代。 
     
    下面是一个例子:
      
    被并行调用的子程序:

    1. <?php 
    2. if($argc==1){ 
    3.          echo("argv "); 
    4. $arg = $argv[1];     
    5. for($i=0; $i<10; $i++) 
    6. echo($i.".1.".time()." exec $arg  "); 
    7. if($arg=='php2') 
    8. sleep(1); 
    9. echo($i.".2.".time()." exec $arg  "); 
    10. sleep(1); 
    11. }else{ 
    12. sleep(1); 
    13. ?> 

    ----------------------------
    主调用者程序,由他调用子进程,同时并发的收集子程序的输出 

    1. <?php 
    2. error_reporting(E_ALL); 
    3.      
    4. $handle1 = popen('php sub.php php1', 'r'); 
    5. $handle2 = popen('php sub.php php2', 'r'); 
    6. $handle3 = popen('php sub.php php3', 'r'); 
    7.      
    8. echo "'$handle1'; " . gettype($handle1) . " "; 
    9. echo "'$handle2'; " . gettype($handle2) . " "; 
    10. echo "'$handle3'; " . gettype($handle3) . " "; 
    11.       
    12. //sleep(20); 
    13. while(!feof($handle1) || !feof($handle2) || !feof($handle3) ){ 
    14. $read = fgets($handle1); 
    15. echo $read; 
    16.       
    17. $read = fgets($handle2); 
    18. echo $read; 
    19.       
    20. $read = fgets($handle3); 
    21. echo $read; 
    22.  
    23.  
    24. pclose($handle1); 
    25. pclose($handle2); 
    26. pclose($handle3); 
    27. ?> 

    -------------------

    下面是我机器上的输出:


    > php exec.php
    'Resource id #4'; resource
    'Resource id #5'; resource
    'Resource id #6'; resource
    0.1.1147935331 exec php1
    0.1.1147935331 exec php2
    0.1.1147935331 exec php3
    1.1.1147935332 exec php1
    0.2.1147935332 exec php2
    1.1.1147935332 exec php3
    2.1.1147935333 exec php1
    1.1.1147935333 exec php2
    2.1.1147935333 exec php3
    3.1.1147935334 exec php1
    1.2.1147935334 exec php2
    3.1.1147935334 exec php3
    4.1.1147935335 exec php1
    2.1.1147935335 exec php2
    4.1.1147935335 exec php3
    5.1.1147935336 exec php1
    2.2.1147935336 exec php2
    5.1.1147935336 exec php3
    6.1.1147935337 exec php1
    3.1.1147935337 exec php2
    6.1.1147935337 exec php3
    7.1.1147935338 exec php1
    3.2.1147935338 exec php2
    7.1.1147935338 exec php3
    8.1.1147935339 exec php1
    4.1.1147935339 exec php2
    8.1.1147935339 exec php3
    9.1.1147935340 exec php1
    4.2.1147935340 exec php2
    9.1.1147935340 exec php3
    5.1.1147935341 exec php2
    5.2.1147935342 exec php2
    6.1.1147935343 exec php2
    6.2.1147935344 exec php2
    7.1.1147935345 exec php2
    7.2.1147935346 exec php2
    8.1.1147935347 exec php2
    8.2.1147935348 exec php2
    9.1.1147935349 exec php2
    9.2.1147935350 exec php2

    **总结:**

    **主程序循环等待子进程, 通过fgets或fread 把子进程的输出获取出来 , 从时间戳上看,的确实现了并发执行。**
      
    -----------------------------------------------
    改进:
      
    *  popen打开的句柄是单向的,如果需要向子进程交互,可以使用proc_open
    *  使用数组和子函数代替while(!feof($handle1) || !feof($handle2) || !feof($handle3) )这种龌龊的写法
    *  用fread一次把子进程已经产生的输出取完,而不是每次一行。


    这是另一个改进:
    一个并发执行shell任务的调度者,本程序读取一个任务文件,把里面的每行命令并发执行, 可以设置同时存在的子进程数目:

    1. <? 
    2. /* 
    3.          主任务管理器 
    4.          并发的执行子任务列表 
    5. */ 
    6.  
    7. include("../common/conf.php"); 
    8. include("../common/function.php"); 
    9.  
    10. //开启的进程数 
    11. $exec_number = 40 ; 
    12.  
    13. /***** main ********/ 
    14. if($argc==1){ 
    15.          echo("argv "); 
    16. $taskfile = $argv[1]; 
    17.  
    18.  
    19. //tasklist 
    20. $tasklist = file($taskfile); 
    21.  
    22.  
    23. $tasklist_len = count($tasklist); 
    24. $tasklist_pos = 0; 
    25.  
    26.  
    27. $handle_list = array(); 
    28.  
    29.  
    30. while(1){ 
    31.  
    32.  
    33.          //子进程列表有空闲,则填充补齐子进程列表 
    34.          if($exec_number > count($handle_list) && 
    35.                              $tasklist_pos < $tasklist_len) 
    36.          { 
    37.                  for($i=$tasklist_pos; $i<$tasklist_len; ) 
    38.                      { 
    39.                              $command = $tasklist[$i] ; 
    40.                              $handle_list[] = popen($command , "r" ); 
    41.                              tolog("begin task   ".$tasklist[$i]); 
    42.                              $i++; 
    43.                              if($exec_number == count($handle_list)) break; 
    44.                      } 
    45.                      $tasklist_pos = $i; 
    46.          } 
    47.  
    48.  
    49.          //如果子进程列表空,退出 
    50.          if(0 == count($handle_list)) 
    51.          { 
    52.                      break; 
    53.          } 
    54.  
    55.  
    56.          //检查子进程列表的输出,把停掉的子进程关闭并记录下来 
    57.          $end_handle_keys = array(); 
    58.          foreach($handle_list as $key => $handle) 
    59.          { 
    60.                      //$str = fgets($handle, 65536); 
    61.                      $str = fread($handle, 65536); 
    62.                      echo($str); 
    63.  
    64.  
    65.                      if(feof($handle)) 
    66.                      { 
    67.                              $end_handle_keys[] = $key; 
    68.                              pclose($handle); 
    69.                      } 
    70.          } 
    71.  
    72.  
    73.          //踢出停掉的子进程 
    74.          foreach($end_handle_keys as $key) 
    75.          { 
    76.                      unset($handle_list[$key]); 
    77.                      //var_dump($handle_list); 
    78.                      //exit; 
    79.          } 
    80.  
    81.  
    82.  
    83.  
    84. tolog(" *******************end********************** ", "" ,     true); 
    85. ?>

     

  • 相关阅读:
    二元树的深度 【微软面试100题 第五十二题】
    和为n连续正数序列 【微软面试100题 第五十一题】
    一道看上去很吓人的算法题 【微软面试去100题 第四十九题】
    在左移的递减数组中查找某数 【微软面试100题 第四十八题】
    最长递减子序列 【微软面试100题 第四十七题】
    括号问题 【微软面试100题 第四十六题】
    矩阵运算 【微软面试100题 第四十五题】
    设计一个魔方(六面)的程序 【微软面试100题 第四十四题】
    二叉搜索树的非递归前中后序遍历 【微软面试100题 第四十三题】
    合并链表 【微软面试100题 第四十二题】
  • 原文地址:https://www.cnblogs.com/wish123/p/3947718.html
Copyright © 2011-2022 走看看