尝试php命令行脚本多进程并发执行
php不支持多线程,但是我们可以把问题转换成“多进程”来解决。由于php中的pcntl_fork只有unix平台才可以使用,所以本文尝试使用popen来替代。
下面是一个例子:
被并行调用的子程序:
- <?php
- if($argc==1){
- echo("argv\n");
- }
- $arg = $argv[1];
- for($i=0; $i<10; $i++)
- {
- echo($i.".1.".time()." exec $arg \n");
- if($arg=='php2')
- {
- sleep(1);
- echo($i.".2.".time()." exec $arg \n");
- sleep(1);
- }else{
- sleep(1);
- }
- ?>
----------------------------
主调用者程序,由他调用子进程,同时并发的收集子程序的输出
- <?php
- error_reporting(E_ALL);
- $handle1 = popen('php sub.php php1', 'r');
- $handle2 = popen('php sub.php php2', 'r');
- $handle3 = popen('php sub.php php3', 'r');
- echo "'$handle1'; " . gettype($handle1) . "\n";
- echo "'$handle2'; " . gettype($handle2) . "\n";
- echo "'$handle3'; " . gettype($handle3) . "\n";
- //sleep(20);
- while(!feof($handle1) || !feof($handle2) || !feof($handle3) ){
- $read = fgets($handle1);
- echo $read;
- $read = fgets($handle2);
- echo $read;
- $read = fgets($handle3);
- echo $read;
- }
- pclose($handle1);
- pclose($handle2);
- pclose($handle3);
- ?>
-------------------
下面是我机器上的输出:
> 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任务的调度者,本程序读取一个任务文件,把里面的每行命令并发执行, 可以设置同时存在的子进程数目:
- <?
- /*
- 主任务管理器
- 并发的执行子任务列表
- */
- include("../common/conf.php");
- include("../common/function.php");
- //开启的进程数
- $exec_number = 40 ;
- /***** main ********/
- if($argc==1){
- echo("argv\n");
- }
- $taskfile = $argv[1];
- //tasklist
- $tasklist = file($taskfile);
- $tasklist_len = count($tasklist);
- $tasklist_pos = 0;
- $handle_list = array();
- while(1){
- //子进程列表有空闲,则填充补齐子进程列表
- if($exec_number > count($handle_list) &&
- $tasklist_pos < $tasklist_len)
- {
- for($i=$tasklist_pos; $i<$tasklist_len; )
- {
- $command = $tasklist[$i] ;
- $handle_list[] = popen($command , "r" );
- tolog("begin task \t ".$tasklist[$i]);
- $i++;
- if($exec_number == count($handle_list)) break;
- }
- $tasklist_pos = $i;
- }
- //如果子进程列表空,退出
- if(0 == count($handle_list))
- {
- break;
- }
- //检查子进程列表的输出,把停掉的子进程关闭并记录下来
- $end_handle_keys = array();
- foreach($handle_list as $key => $handle)
- {
- //$str = fgets($handle, 65536);
- $str = fread($handle, 65536);
- echo($str);
- if(feof($handle))
- {
- $end_handle_keys[] = $key;
- pclose($handle);
- }
- }
- //踢出停掉的子进程
- foreach($end_handle_keys as $key)
- {
- unset($handle_list[$key]);
- //var_dump($handle_list);
- //exit;
- }
- }
- tolog("\n\n*******************end**********************\n\n", "" , true);
- ?>
尝试php命令行脚本多进程并发执行的更多相关文章
- linux shell并发执行命令
一般我们在linux上十一shell命令的批量执行操作,一般使用for或者while 循环进行操作,但是这样有一个问题,for或者while本质上是串行的,并不能,如果某一个命令执行耗费的时间比较长, ...
- Linux Shell多进程并发以及并发数控制
1. 基础知识准备 1.1. linux后台进程 Unix是一个多任务系统,允许多用户同时运行多个程序.shell的元字符&提供了在后台运行不需要键盘输入的程序的方法.输入命令后,其后紧跟&a ...
- python多进程并发
由于Python下调用Linux的Shell命令都需要等待返回,所以常常我们设置的多线程都达不到效果,因此在调用shell命令不需要返回时,使用threading模块并不是最好的方法. http: ...
- Appium+python自动化(三十六)- 士兵突击许三多 - 多个appium服务启动,多个设备启动,多进程并发启动设备-并发测试 - 上(超详解)
简介 前面课程只是启动了单个appium服务,只能控制单台设备.如果需要针对多台设备测试那么该如何处理?而且发现群里的小伙伴们也在时不时地在讨论这个问题,想知道怎么实现的,于是宏哥就决定写一片这样的文 ...
- 【说解】在shell中通过mkfifo创建命名管道来控制多个进程并发执行
背景: 工作中有两个异地机房需要传数据,数据全名很规范,在某个目录下命名为统一的前缀加上编号.如/path/from/file.{1..100}.而机房间的专线对单个scp进程的传输速度是有限制的,比 ...
- 正尝试在 OS 载入程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内执行托管代码,这样做会导致应用程序挂起。
出错提示: 正尝试在 OS 载入程序锁内执行托管代码. 不要尝试在 DllMain 或映像初始化函数内执行托管代码,这样做会导致应用程序挂起. 原因分析: .NET2.0中添加了42种非常强大的调试助 ...
- 使用pabot并发执行robotframework的testSuite
下载robotremoteserver-1.0.1.tar.gz.robotframework-pabot-0.22.tar.gz 执行以下命令,以安装pabot: pip install robot ...
- Python多进程并发(multiprocessing)用法实例详解
http://www.jb51.net/article/67116.htm 本文实例讲述了Python多进程并发(multiprocessing)用法.分享给大家供大家参考.具体分析如下: 由于Pyt ...
- 多线程并发执行任务,取结果归集。终极总结:Future、FutureTask、CompletionService、CompletableFuture
目录 1.Futrue 2.FutureTask 3.CompletionService 4.CompletableFuture 5.总结 ================正文分割线========= ...
随机推荐
- ubuntu如何杀死进程
一.得到所有进程 先用命令查询出所有进程 ps -ef 二.杀死进程 我们使用ps -ef命令之后,就会得到一些列进程信息,有进程pid什么的,如果你要杀死莫个进程的话,直接使用命令 kill ...
- Jenkins+SVN+Maven发布项目
一.安装jenkins插件 登入Jenkis后,安装几个插件: Maven Integration plugin # 没有这个插件,不能创建maven项目 Subversion Plug-in Pub ...
- 基础知识:BT1120
今天谈点我所理解的BT1120协议. BT1120是高清晰度电视 (HDTV) 演播室信号数字接口,首先说一下接口标准里面的概念,然后谈谈自己的理解,写这个文章的目的就是解释给自己听的,所以都是一些白 ...
- ZOJ 3778 C - Talented Chef 水题
LINK:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3778 题意:有n道菜,每道菜需要\(a_i\)道工序,有m个锅可 ...
- C++ 的getline问题
在用c++的getline函数的时候碰到两个问题,总结如下: 1.有时候写程序的时候我们会发现getline(cin,str);这样的语句是不会执行,而是直接跳过的, 一般的解决方法是getline一 ...
- 2、java语言基础
1.关键字 被Java语言赋予特定含义的单词被称为关键字关键字都是小写的在Java开发工具中,针对关键字有特殊颜色的标记 2.标识符 Java标识符命名规则 ·标识符是由,数字,字母,下划线和美元符号 ...
- js-打地鼠游戏开发
[生成画布] 第1课[随机生成地鼠] 第2课[定时生成地鼠] 第3课[打地鼠完结篇] 第4课 优酷在线播放地址 http://list.youku.com/albumlist/show?id=2939 ...
- JS 判断手机操作系统代码
还是利用UA, 返回值: ios, android, unknown function getMobileType () { var ua = window.navigator.userAgent.t ...
- julia 1.0如何使用pkg
输入]进入pkg模式 add 加包名即可安装,如 add Cxx
- VirtualBox与Genymotion命令行启动
一.VirtualBox命令行启动 1.添加环境变量: %programfiles%\Oracle\VirtualBox 2.用VBoxManage查看已存在vmname|uuid命令: VBoxMa ...