定义
进程就是正在运行的程序的一个实例。
例如,我们在某个终端去执行一个php脚本,这个时候就可以认为是开启了一个进程。
基本使用
1. 创建一个子进程对象
// 普通形式
$process = new swoole_process('callback_function', true);
// oop形式
swoole_process::__construct(callable $function, $redirect_stdin_stdout = false, $create_pipe = true);
// 启用命名空间
Swoole\Process::__construct(callable $function, $redirect_stdin_stdout = false, $create_pipe = true)
参数说明
-
$function
,子进程创建成功后要执行的函数,底层会自动将函数保存到对象的callback属性上。如果希望更改执行的函数,可赋值新的函数到对象的callback属性。 -
$redirect_stdin_stdout
,重定向子进程的标准输入和输出。启用此选项后,在子进程内输出内容将不是打印屏幕,而是写入到主进程管道。读取键盘输入将变为从管道中读取数据。默认为阻塞读取。 -
$pipe_type
,管道类型,启用$redirect_stdin_stdout
后,此选项将忽略用户参数,强制为1。如果子进程内没有进程间通信,可以设置为 0
管道类型
0:不创建管道
1:创建SOCK_STREAM类型管道
2:创建SOCK_DGRAM类型管道
启用$redirect_stdin_stdout 后,此选项将忽略用户参数,强制为1。
管道类型为DGRAM
数据报时,read可以读取完整的一个数据包。
管道类型为STREAM
时,read是流式的,需要自行处理包完整性问题。
对于数据完整性要求较高时,强烈建议不开启 $redirect_stdin_stdout。
2. 启动子进程
function swoole_process->start()
创建成功返回子进程的PID,创建失败返回false。
可使用swoole_errno和swoole_strerror得到错误码和错误信息。
-
$process->pid
属性为子进程的PID -
$process->pipe
属性为管道的文件描述符
执行后子进程会保持父进程的内存和资源,如父进程内创建了一个redis连接,那么在子进程会保留此对象,所有操作都是对同一个连接进行的。
3. 往管道写入数据
function Process->write(string $data);
-
在子进程内调用write,父进程可以调用read接收此数据
-
在父进程内调用write,子进程可以调用read接收此数据
4. 从管道中读取数据
function Process->read(int $buffer_size=8192)
读取成功返回二进制数据字符串,读取失败返回false。
5. 执行外部程序
function Process->exec(string $execfile, array $args)
-
$execfile
指定可执行文件的绝对路径,如 “/usr/bin/python” -
$args
是一个数组,是exec的参数列表,如 array(‘test.py’, 123),相当与python test.py 123
特别注意
$execfile
必须使用绝对路径,否则会报文件不存在错误。
由于exec系统调用会使用指定的程序覆盖当前程序,子进程需要读写标准输出与父进程进行通信。
如果未指定redirect_stdin_stdout = true,执行exec后子进程与父进程无法通信。
简单例子
// 1.创建子进程对象
$process = new swoole_process(function(swoole_process $pro){
// 3.调用外部程序
$pro->exec("/usr/local/php/bin/php",[__DIR__.'../server/http.php']);
}, true);
// 2.启动子进程
$pid = $process->start();
echo "子进程id:".$pid.PHP_EOL;
// 4.回收子进程
swoole_process::wait();
使用场景
需求
有10个url地址,需要获取这10个地址里面的内容,写入文件或数据库。
PHP原始方案
同步执行这10个url,顺序获取一个个url里的内容。
问题:执行慢
Swoole process方案
引入swoole process,按需开启多个子进程执行。
例子
<?php
// 进程讲解例子
// 开始标志
echo "process-start-time".date("Ymd H:i:s").PHP_EOL;
// 1.定义子进程对象数组
$workers = [];
// 2.定义url数组
$urls = [
'http:www.baidu.com',
'http:www.qq.com',
'http:www.sina.com',
'http:www.jd.com',
'http:www.imooc.com',
'http:www.taobao.com',
];
// 3.PHP原生做法
// foreach($urls as $url){
// $content[] = file_get_contents($url);
// }
// 3.swoole process做法
for($i = 0; $i < 6; $i++){
// 4.创建子进程对象
$process = new swoole_process(function(swoole_process $worker) use($i, $urls) {
// 5.调用自定义方法
$content = curlData($urls[$i]);
//echo $content.PHP_EOL;
// 6.往管道里写入内容
$worker->write($content.PHP_EOL);
},true);
// 7.启动子进程
$pid = $process->start();
// 8.把子进程对象加到workers数组
$workers[$pid] = $process;
}
// 9.打印workers
foreach ($workers as $process) {
echo $process->read();
}
// 结束标志
echo "process-end-time".date("Ymd H:i:s");
// 自定义方法(模拟场景,非真实代码)
function curlData($url){
sleep(1);
return $url."success".PHP_EOL;
}