优雅的玩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 & 数据驱动>中,也对它 ...
随机推荐
- sql的sum函数(与group by,having子句混合使用)
SELECT Customer,SUM(OrderPrice) FROM Orders WHERE Customer='Bush' OR Customer='Adams' GROUP BY Custo ...
- OpenCV实现仿射变换
什么是仿射变换?¶ 一个任意的仿射变换都能表示为 乘以一个矩阵 (线性变换) 接着再 加上一个向量 (平移). 综上所述, 我们能够用仿射变换来表示: 旋转 (线性变换) 平移 (向量加) 缩放操作 ...
- 【56】java本地文件File类详解
1.java类的介绍 public class File extends Object implements Serializable, Comparable<File> 文件和目录路径名 ...
- 数据挖掘进阶之序列模式分析算法GSP的实现
序列模式分析算法GSP的实现 一.算法简介 序列模式定义:给定一个由不同序列组成的集合,其中,每个序列由不同的元素按顺序有序排列,每个元素由不同项目组成,同时给定一个用户指定的最小支持度阈值,序列模式 ...
- 阿里云 云服务器 CentOS 5.8 安装 php 5.4
1.安装php http://webtatic.com/packages/php54/ 2.安装mysql http://webtatic.com/packages/mysql55/ 3.修改mysq ...
- obj-c编程15[Cocoa实例02]:KVC和KVO的实际运用
我们在第16和第17篇中分别介绍了obj-c的KVC与KVO特性,当时举的例子比较fun,太抽象,貌似和实际不沾边哦.那么下面我们就用一个实际中的例子来看看KVC与KVO是如何运用的吧. 该例中用到了 ...
- javascript中的in运算符
in运算符希望它的左操作数是一个字符串或可以转换为字符串,希望他的又操作数是一个对象:如果右侧对象拥有一个名为左操作数值的属性名,那么表达式返回true: var point = {x:1,y:1}; ...
- Spring Kafka和Spring Boot整合实现消息发送与消费简单案例
本文主要分享下Spring Boot和Spring Kafka如何配置整合,实现发送和接收来自Spring Kafka的消息. 先前我已经分享了Kafka的基本介绍与集群环境搭建方法.关于Kafka的 ...
- 从小故事来谈nginx负载均衡
负载均衡 负载均衡是任何一个有一定规模的互联网企业都会考虑的问题,负载方式很多,有依靠硬件实现的,也有依靠软件实现负载的. 今天来聊聊使用软件来负载的方式 你可能听过各自负载的方式,比如常见的ngin ...
- [ASP.NET MVC4高级编程] 学习记录(一)
理论: 先有GUI在发展,当用户按下某个键,某个进程会监听到这个动作,这个进程就是控制器.这就是MVC模式. 后来有了事件驱动编程,响应动作的是按钮本身,而不是控制器. 再后来webForm中,事件驱 ...