尝试php命令行脚本多进程并发执行

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

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

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

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

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

下面是我机器上的输出:

> 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. include("../common/conf.php");
  7. include("../common/function.php");
  8. //开启的进程数
  9. $exec_number = 40 ;
  10. /***** main ********/
  11. if($argc==1){
  12. echo("argv\n");
  13. }
  14. $taskfile = $argv[1];
  15. //tasklist
  16. $tasklist = file($taskfile);
  17. $tasklist_len = count($tasklist);
  18. $tasklist_pos = 0;
  19. $handle_list = array();
  20. while(1){
  21. //子进程列表有空闲,则填充补齐子进程列表
  22. if($exec_number > count($handle_list) &&
  23. $tasklist_pos < $tasklist_len)
  24. {
  25. for($i=$tasklist_pos; $i<$tasklist_len; )
  26. {
  27. $command = $tasklist[$i] ;
  28. $handle_list[] = popen($command , "r" );
  29. tolog("begin task \t ".$tasklist[$i]);
  30. $i++;
  31. if($exec_number == count($handle_list)) break;
  32. }
  33. $tasklist_pos = $i;
  34. }
  35. //如果子进程列表空,退出
  36. if(0 == count($handle_list))
  37. {
  38. break;
  39. }
  40. //检查子进程列表的输出,把停掉的子进程关闭并记录下来
  41. $end_handle_keys = array();
  42. foreach($handle_list as $key => $handle)
  43. {
  44. //$str = fgets($handle, 65536);
  45. $str = fread($handle, 65536);
  46. echo($str);
  47. if(feof($handle))
  48. {
  49. $end_handle_keys[] = $key;
  50. pclose($handle);
  51. }
  52. }
  53. //踢出停掉的子进程
  54. foreach($end_handle_keys as $key)
  55. {
  56. unset($handle_list[$key]);
  57. //var_dump($handle_list);
  58. //exit;
  59. }
  60. }
  61. tolog("\n\n*******************end**********************\n\n", "" ,     true);
  62. ?>
时间: 2024-08-27 19:14:49

尝试php命令行脚本多进程并发执行的相关文章

shell模拟并发执行

参考: http://www.51testing.com/html/28/116228-238978.html http://blog.chinaunix.net/uid-27571599-id-3473078.html         在bash中,使用后台任务来实现任务的多进程化.在不加控制的模式下,不管有多少任务,全部都后台执行.也就是说,在这种情况下,有多少任务就有多少"进程"在同时执行.   实例一:正常脚本(脚本功能:查看一个文件中的IP列表循环测试主机连通性) [[ema

Linux Shell多进程并发以及并发数控制

1. 基础知识准备 1.1. linux后台进程 Unix是一个多任务系统,允许多用户同时运行多个程序.shell的元字符&提供了在后台运行不需要键盘输入的程序的方法.输入命令后,其后紧跟&字符,该命令就会被送往到linux后台执行,而终端又可以继续输入下一个命令了. 比如: sh a.sh & sh b.sh & sh c.sh & 这三个命令就会被同时送往linux后台执行,在这个程度上,认为这三个命令并发执行了. 1.2. linux文件描述符 文件描述符(缩

shell中控制多个进程并发执行的方法

shell中实现多进程实际上就是将多个任务放到后台中执行而已,但是现在需要控制多进程并发的数量该如何实现呢?别急,我们一步一步来实现这个目标,首先从最原始的串行执行开始: #!/bin/bash start=`date +%s` for i in $(seq 1 5); do echo test sleep 2 done end=`date +%s` time=$(($end - $start)) echo "time: $time" 执行结果: # sh test1.sh test

002-Shell的并发执行原理及其实现

1.正常执行 如果是多个命令执行的话,默认是串行执行的.如果前面的一个任务没有执行完成,后面的任务就无法执行,即不可能将指令置于CPU上执行. sleep 10 后台执行.Default模式下,shell命令是阻塞执行的,可以通过其后添加&让这条命令异步执行,如: sleep 10 & 执行这条命令后,并不会阻塞10秒,而是立即返回. 2.并行执行 注意:这里的并行执行如果是单核CPU的话,实际上指的是并发执行.并发执行是具备并行执行的前提因素. 如果将这种方法用在while循环中,则可以

Shell脚本中的多任务并发执行

正常情况下,Shell脚本中的命令是串行执行的,当一条命令执行完才会执行接下来的命令.比如下面这段代码: #!/bin/bash for i in {1..10};do echo $i done echo "END" 执行结果: 1 2 3 4 5 6 7 8 9 10 END 可以看到,循环体中的"echo $i"命令是串行执行的.但是如果所执行的命令耗时比较长,这就会导致整个程序的执行时间非常长,甚至可能导致程序执行时卡在那里,长时间失去响应.比如我们需要完成这

[Linux]shell多进程并发—详细版

业务背景 schedule.sh脚本负责调度用户轨迹工程脚本的执行,截取部分代码如下: #!/bin/bash source /etc/profile; export userTrackPathCollectHome=/home/pms/bigDataEngine/analysis/script/usertrack/master/pathCollect ############################## # # 流程A # ##############################

Python多进程并发(multiprocessing)用法实例详解

http://www.jb51.net/article/67116.htm 本文实例讲述了Python多进程并发(multiprocessing)用法.分享给大家供大家参考.具体分析如下: 由于Python设计的限制(我说的是咱们常用的CPython).最多只能用满1个CPU核心.Python提供了非常好用的多进程包multiprocessing,你只需要定义一个函数,Python会替你完成其他所有事情.借助这个包,可以轻松完成从单进程到并发执行的转换. 1.新建单一进程 如果我们新建少量进程,

linux下通过命令启动多个终端执行相应的命令和程序

    作者:张昌昌 在一些情况下,往往需要同时启动多个终端并让终端执行自动执行相应的命令,进而达到提高操作效率的目的.在linux下gnome-terminal启动终端命令, gnome-terminal -x 后跟执行的命令,bash是linux启动子shell的命令,bash -c "所要执行的命令串",通过嵌套gnome-terminal -x bash -c ......,表示启动新终端, 并在新启动的终端里执行bash -c,即启动子shell,由子shell执行-c后面的

PHP的命令行脚本开发

PHP能做什么 PHP官方文档不要脸的说PHP能做任何事,这和业界广为流传气死其他程序员不偿命的PHP是最好的语言可真是遥呼相应. PHP主要用于以下三个领域 (1) 服务端脚本 这是最主要的领域,PHP 解析器(CGI 或者服务器模块)和web服务器(如Apache.Nginx)搭配使用. (2) 命令行脚本 这种方式,仅仅只需要 PHP 解析器来执行.联想一下Python就会明白. (3) 桌面应用程序 通过一些扩展库如PHP-GTK可以使用PHP编写桌面应用程序.不过这得多无聊才会去干这事