优雅的玩PHP多进程
proc_open
(PHP 4 >= 4.3.0, PHP 5, PHP 7)
proc_open — 执行一个命令,并且打开用来输入/输出的文件指针。
说明¶
$cmd
, array $descriptorspec
, array &$pipes
[, string$cwd
[, array $env
[, array $other_options
]]] )类似 popen() 函数, 但是 proc_open() 提供了更加强大的控制程序执行的能力。
参数¶
cmd
-
要执行的命令
descriptorspec
-
一个索引数组。 数组的键表示描述符,数组元素值表示 PHP 如何将这些描述符传送至子进程。 0 表示标准输入(stdin),1 表示标准输出(stdout),2 表示标准错误(stderr)。
数组中的元素可以是:
- 包含了要传送至进程的管道的描述信息。 第一个元素为描述符类型, 第二个元素是针对该描述符的选项。 有效的类型有:pipe (第二个元素可以是: r 向进程传送该管道的读取端,w 向进程传送该管道的写入端), 以及 file(第二个元素为文件名)。
- 表达一个真实文件描述符的流资源类型 (例如:已打开的文件,一个 socket 端口,
STDIN
)。
文件描述符的值不限于 0,1 和 2,你可以使用任何有效的文件描述符 并将其传送至子进程。 这使得你的脚本可以和其他脚本交互操作。 例如,可以通过指定文件描述符将密码以更加安全的方式 传送至诸如 PGP,GPG 和 openssl 程序, 同时也可以很方便的获取这些程序的状态信息。
pipes
-
将被置为索引数组, 其中的元素是被执行程序创建的管道对应到 PHP 这一端的文件指针。
cwd
-
要执行命令的初始工作目录。 必须是 绝对 路径, 设置此参数为
NULL
表示使用默认值(当前 PHP 进程的工作目录)。 env
-
要执行的命令所使用的环境变量。 设置此参数为
NULL
表示使用和当前 PHP 进程相同的环境变量。 other_options
-
你还可以指定一些附加选项。 目前支持的选项包括:
- suppress_errors (仅用于 Windows 平台): 设置为
TRUE
表示抑制本函数产生的错误。 - bypass_shell (仅用于 Windows 平台): 设置为
TRUE
表示绕过 cmd.exe shell。
- suppress_errors (仅用于 Windows 平台): 设置为
返回值¶
返回表示进程的资源类型, 当使用完毕之后,请调用 proc_close() 函数来关闭此资源。 如果失败,返回 FALSE
。
更新日志¶
版本 | 说明 |
---|---|
5.2.1 | 为 other_options 参数增加 bypass_shell 选项。 |
范例¶
Example #1 proc_open() 例程
<?php
$descriptorspec = array(
0 => array("pipe", "r"), // 标准输入,子进程从此管道中读取数据
1 => array("pipe", "w"), // 标准输出,子进程向此管道中写入数据
2 => array("file", "/tmp/error-output.txt", "a") // 标准错误,写入到一个文件
);
$cwd = '/tmp';
$env = array('some_option' => 'aeiou');
$process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);
if (is_resource($process)) {
// $pipes 现在看起来是这样的:
// 0 => 可以向子进程标准输入写入的句柄
// 1 => 可以从子进程标准输出读取的句柄
// 错误输出将被追加到文件 /tmp/error-output.txt
fwrite($pipes[0], '<?php print_r($_ENV); ?>');
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
// 切记:在调用 proc_close 之前关闭所有的管道以避免死锁。
$return_value = proc_close($process);
echo "command returned $return_value\n";
}
?>
以上例程的输出类似于:
Array
(
[some_option] => aeiou
[PWD] => /tmp
[SHLVL] => 1
[_] => /usr/local/bin/php
)
command returned 0
注释¶
Note:
Windows 兼容性:超过 2 的描述符也可以作为可继承的句柄传送到子进程。 但是,由于 Windows 的架构并不将文件描述符和底层句柄进行关联, 所以,子进程无法访问这样的句柄。 标准输入,标准输出和标注错误会按照预期工作。
Note:
如果你只需要单向的进程管道, 使用 popen() 函数会更加简单。
<?php
#popen.php
$process = array();
for($i=0;$i<5;$i++)
{
echo $i.' opening ... '.chr(10);
$process[$i] = popen('php '.dirname(__FILE__).'/popen_child.php', 'w');
sleep(1);
} echo 'OK>>'.chr(10);
sleep(3);
for($i=0;$i<5;$i++)
{
$read = fread($process[$i], 64);
echo $read;
pclose($process[$i]);
echo $i.' closed'.chr(10);
sleep(1);
}
<?php
#popen_child.php
while(1)
{
$echo =getmypid() .'->'. date("YmHis").chr(10);
echo $echo ;
system('echo '.$echo.'> logp');
sleep(5);
}
例子1(popen):
<?php
function foo() {
echo date('Y-m-d H:i:s')."\n";
echo shell_exec('php -r \'sleep(1); echo date("Y-m-d H:i:s")." by shell_exec:blocking\n";\''); //阻塞
$pipe1 = popen('php -r \'sleep(2); echo date("Y-m-d H:i:s")." by popen1:non-blocking\n";\'', 'r'); //非阻塞(管道)
$pipe2 = popen('php -r \'sleep(1); echo date("Y-m-d H:i:s")." by popen2:non-blocking\n";\'', 'r'); //非阻塞(管道)
echo date('Y-m-d H:i:s')."\n";
register_shutdown_function(function() use ($pipe1, $pipe2) { //事件驱动(脚本结束事件),异步回调
echo stream_get_contents($pipe1); //输出子进程返回的数据
echo stream_get_contents($pipe2); //输出子进程返回的数据
pclose($pipe1);
pclose($pipe2);
});
}
foo();
//输出
2016-09-11 20:25:30
2016-09-11 20:25:31 by shell_exec:blocking
2016-09-11 20:25:31
2016-09-11 20:25:33 by popen1:non-blocking
2016-09-11 20:25:32 by popen2:non-blocking 例子2(proc_open):
<?php
function foo() {
$proc = proc_open(
//task.php 内容为 $arr = unserialize(stream_get_contents(STDIN)); $arr['time'] = date('Y-m-d H:i:s', $arr['time']); echo serialize($arr);
'/png/php/5.4.45/bin/php /home/eechen/task.php',
array(
0 => array('pipe','r'), //stdin (用fwrite写入数据给管道)
1 => array('pipe','w'), //stdout(用stream_get_contents获取管道输出)
2 => array('pipe','w'), //stderr(用stream_get_contents获取管道输出)
//2 => array('file','/tmp/err.txt','a') //stderr(写入到文件)
),
$pipes, //管道(stdin/stdout/stderr)
'/tmp', //当前PHP进程的工作目录
array('foo' => 'bar') //php.ini 配置 variables_order = "EGPCS" 其中E表示$_ENV,否则$_ENV输出为空
);
//var_dump($pipes); //resource of type (stream)
if(is_resource($proc)) {
//stdin
$stdin = serialize(array('time' => time()));
fwrite($pipes[0], $stdin); //把参数传给脚本task.php
fclose($pipes[0]); //fclose关闭管道后proc_close才能退出子进程,否则会发生死锁
register_shutdown_function(function() use($pipes, $proc) { //事件驱动(脚本结束事件),异步回调
//stdout
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
//stderr
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
//exit code (返回进程的终止状态码,如果发生错则返回-1)
$status = proc_close($proc);
$data = array(
'stdout' => $stdout,
'stderr' => $stderr,
'status' => $status,
);
var_export($data); //echo json_encode($data);
});
}
}
foo();
//输出:
array (
'stdout' => 'a:1:{s:4:"time";s:19:"2016-09-11 21:26:29";}',
'stderr' => '',
'status' => 0,
)
优雅的玩PHP多进程的更多相关文章
- 我也来----xia bi bi 一下----微信小程序
工作刚到一阶段 就看了看微信小程序 自己做了个小dome 主要是为了让我女朋友能够学习做菜! 然而悲催的发现我根本没有App ID 不说快了 直接上图 个人感觉开发起来还是很简单的. 对着AP ...
- zcelib - One cplusplus C++ crossplatform library use for develop server,similar to ACE.
zcelib - One cplusplus C++ crossplatform library use for develop server,similar to ACE.OS适配层,为了适应WIN ...
- Java public 和 private 访问修饰符
何为封装 从事面向对象编程的 Java 程序员,不可能不知道封装,它是面向对象编程的精髓,非常重要. 那什么是封装?字面意思就是把摆在外面的东西包起来. 一句话,封装就是对外隐藏内部细节. 那为何要封 ...
- 优雅地乱玩Linux-6-Chrome端SSH插件
文章最初发表于szhshp的第三边境研究所转载请注明 优雅地乱玩Linux-6-Chrome端SSH插件 最近注册了个AWS,免费一年,一年内可以各种乱玩~ 从自己的电脑连接云主机一般需要SSH这样的 ...
- 玩转nodeJS系列:使用cluster创建nodejs单机多核集群(多进程)
前言: nodejs提供了cluster集群(支持端口共享的多进程),cluster基于child_process,process二次封装,方便我们使用该功能实现单机nodejs的web集群. 1.c ...
- Nginx深入详解之多进程网络模型
一.进程模型 Nginx之所以为广大码农喜爱,除了其高性能外,还有其优雅的系统架构.与Memcached的经典多线程模型相比,Nginx是经典的多进程模型.Nginx启动后以daemon ...
- 【转】 Nginx深入详解之多进程网络模型
[转自]http://blog.chinaunix.net/uid-22312037-id-3974068.html 一.进程模型 Nginx之所以为广大码农喜爱,除了其高性能外,还有其 ...
- 如何优雅地使用 Windows 10 ?
身为一个伪电脑Geek,就算不懂电脑,也要把那些更不懂电脑的人给唬住. 1.入门级别: 当然就是让别人从视觉上感觉你的电脑不一般啦 第一步:桌面要干净,干净到什么程度呢,要像这样 当别人第一眼看到你的 ...
- [小北De编程手记] : Lesson 06 玩转 xUnit.Net 之 定义自己的FactAttribute
xUnit.Net本身提供了标记测试方法的标签Fact和Theory.在前面的文章<Lesson 02 玩转 xUnit.Net 之 基本UnitTest & 数据驱动>中,也对它 ...
随机推荐
- Hibernate统计表中的条数
/** * 判断积分日志表中是否有某个用户的注册日志 */@Transactional(propagation = Propagation.REQUIRED)public boolean isE ...
- Android ORM 框架之 greenDAO
前言 我相信,在平时的开发过程中,大家一定会或多或少地接触到 SQLite.然而在使用它时,我们往往需要做许多额外的工作,像编写 SQL 语句与解析查询结果等.所以,适用于 Android 的ORM ...
- 苹果新的编程语言 Swift 语言进阶(八)--属性
属性是特定类.结构或枚举的相关值,属性根据作用域不同分为实例属性与类型属性,还可以根据是否存储分为存储属性和计算属性. 1.1 实例属性 为一个类.结构或枚举定义的属性默认属于实例属性,即该属性属于为 ...
- 嵌入式C实战项目开发技巧:如果对一个有规律的数组表进行位移操作
在嵌入式项目开发中,LED灯的操作是一定要会的,也是基础中的基础,比如用51单片机写个跑马灯,这不简单嘛,定义一个数组把那8个跑马灯存起来,然后搞个for循环不就可以了嘛,但是,实际工作开发中写一个跑 ...
- 解决Cell重用内容混乱的几种简单方法,有些方法会增加内存
重用实现分析 查看UITableView头文件,会找到NSMutableArray* visiableCells,和NSMutableDictnery* reusableTableCells两个结构 ...
- vimgrep 搜索总结
vimgrep /匹配模式/[g][j] 要搜索的文件/范围 g:表示是否把每一行的多个匹配结果都加入 j:表示是否搜索完后定位到第一个匹配位置 vimgrep /pattern/ % ...
- leetCode之旅(14)-Number of 1 Bits
题目描述: Write a function that takes an unsigned integer and returns the number of '1' bits it has (als ...
- 如何成为一个优秀的DBA
今天在群上跟技术友们聊天.发现有几个大学生,他们很担心自己找不到工作.我问他们理由,他们说我们没有经验,公司不要怎么办?这些孩子们的担心,让我感觉到奇怪. 如果我是一个公司的老总,我会有这两种考虑:要 ...
- 信息化建设中的IT规划精要
IT规划在信息化建设中发挥着"定位"和"导航"的作用,IT规划理论方法更是博大精深,细细讲来,会成为IT版本的"一千零一夜".因此,本文以& ...
- Django Push 的一些资料
先来中文的: 主要讲Orbited: http://sunsetsunrising.com/2009/django_comet.html#gsc.tab=0 再来英文的: http://www.rkb ...