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. ?>

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

  1. linux shell并发执行命令

    一般我们在linux上十一shell命令的批量执行操作,一般使用for或者while 循环进行操作,但是这样有一个问题,for或者while本质上是串行的,并不能,如果某一个命令执行耗费的时间比较长, ...

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

    1. 基础知识准备 1.1. linux后台进程 Unix是一个多任务系统,允许多用户同时运行多个程序.shell的元字符&提供了在后台运行不需要键盘输入的程序的方法.输入命令后,其后紧跟&a ...

  3. python多进程并发

    由于Python下调用Linux的Shell命令都需要等待返回,所以常常我们设置的多线程都达不到效果,因此在调用shell命令不需要返回时,使用threading模块并不是最好的方法.   http: ...

  4. Appium+python自动化(三十六)- 士兵突击许三多 - 多个appium服务启动,多个设备启动,多进程并发启动设备-并发测试 - 上(超详解)

    简介 前面课程只是启动了单个appium服务,只能控制单台设备.如果需要针对多台设备测试那么该如何处理?而且发现群里的小伙伴们也在时不时地在讨论这个问题,想知道怎么实现的,于是宏哥就决定写一片这样的文 ...

  5. 【说解】在shell中通过mkfifo创建命名管道来控制多个进程并发执行

    背景: 工作中有两个异地机房需要传数据,数据全名很规范,在某个目录下命名为统一的前缀加上编号.如/path/from/file.{1..100}.而机房间的专线对单个scp进程的传输速度是有限制的,比 ...

  6. 正尝试在 OS 载入程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内执行托管代码,这样做会导致应用程序挂起。

    出错提示: 正尝试在 OS 载入程序锁内执行托管代码. 不要尝试在 DllMain 或映像初始化函数内执行托管代码,这样做会导致应用程序挂起. 原因分析: .NET2.0中添加了42种非常强大的调试助 ...

  7. 使用pabot并发执行robotframework的testSuite

    下载robotremoteserver-1.0.1.tar.gz.robotframework-pabot-0.22.tar.gz 执行以下命令,以安装pabot: pip install robot ...

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

    http://www.jb51.net/article/67116.htm 本文实例讲述了Python多进程并发(multiprocessing)用法.分享给大家供大家参考.具体分析如下: 由于Pyt ...

  9. 多线程并发执行任务,取结果归集。终极总结:Future、FutureTask、CompletionService、CompletableFuture

    目录 1.Futrue 2.FutureTask 3.CompletionService 4.CompletableFuture 5.总结 ================正文分割线========= ...

随机推荐

  1. 题解 P2762 【太空飞行计划问题】

    P2762 太空飞行计划问题 题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,-,Em},和进 ...

  2. Ajax-更新

    ajax是与服务器进行(异步/同步)交互的技术之一交互就是对服务器一种访问ajax对服务器进行交互时页面不刷新ajax的语言载体是JS 比如我在百度输入个东西 自动弹出信息像和一些搜索字体相关的页面标 ...

  3. Python学习笔记(二十)调试

    摘抄自: https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143191557 ...

  4. each()和eq()

    今天工作的时候要遍历一个表格,于是我就想到了each(),也没看文档就开始写,大概是这么写的 $(".class").each(function(){ this.click(fun ...

  5. 【CodeForces】913 F. Strongly Connected Tournament 概率和期望DP

    [题目]F. Strongly Connected Tournament [题意]给定n个点(游戏者),每轮游戏进行下列操作: 1.每对游戏者i和j(i<j)进行一场游戏,有p的概率i赢j(反之 ...

  6. 正则表达式:Python 模块 re 简介

    为了使文章更具可读性,本文将正则表达式冗长的 语法介绍 放在了文章的末尾. 一.正则表达式简介 正则表达式(RegExp)是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(元字符 ...

  7. jquery实现简单轮播

    先上简单的html代码 <!DOCTYPE HTML> <html> <head> <link rel="stylesheet" type ...

  8. 1-编程基础及Python环境部署

    目录 1 编程基础 1.1 基本概念 1.2 语言分类 1.3 高级语言的发展 2 程序 3 python的语言介绍 4 Python的解释器 5 Python版本区别 6 Python安装 6.1 ...

  9. 6 - Python内置结构 - 字典

    目录 1 字典介绍 2 字典的基本操作 2.1 字典的定义 2.2 字典元素的访问 2.3 字典的增删改 3 字典遍历 3.1 遍历字典的key 3.2 遍历字典的value 3.3 变量字典的键值对 ...

  10. 健身VS不健身,完全是两种不同的人生!

    这两天一组同龄人合照 刷爆了国内健身圈, 图左是一位67岁的老人, 图右是67岁的健美运动员杨新民老师 相同年龄, 但从外观上有着强烈的距离感! 让多人不禁感叹,健身和不健身, 简直就是两种状态,两种 ...