专栏首页Web技术布道师swoole_proces实现多进程

swoole_proces实现多进程

简介 swoole_process 是swoole提供的进程管理模块,用来替代PHP的pcntl扩展。

首先,确保安装的swoole版本大于1.7.2:

$ php --ri swooleswooleswoole support => enabledVersion => 1.10.1

实例说明 本例里待消费的是三个shell命令,会分别创建一个子进程来消费。消费的时候故意sleep了1秒,以便直观看到效果。

process_t1.php

<?php$start_time = microtime(TRUE);$cmds = [    "uname",    "date",    "whoami"];foreach ($cmds as $cmd) {    $process = new swoole_process( "my_process", true);    $process->start();    $process->write($cmd); //通过管道发数据到子进程。管道是单向的:发出的数据必须由另一端读取。不能读取自己发出去的    echo $rec = $process->read();//同步阻塞读取管道数据}//子进程创建成功后要执行的函数function my_process(swoole_process $worker){    sleep(1);//暂停1s    $cmd = $worker->read();    // $return = exec($cmd);//exec只会输出命令执行结果的最后一行内容,且需要显式打印输出    ob_start();    passthru($cmd);//执行外部程序并且显示未经处理的、原始输出,会直接打印输出。    $return = ob_get_clean();    if(!$return) $return = 'null';    $worker->write($return);//写入数据到管道}//子进程结束必须要执行wait进行回收,否则子进程会变成僵尸进程while($ret = swoole_process::wait()){// $ret 是个数组 code是进程退出状态码,    $pid = $ret['pid'];    echo PHP_EOL."Worker Exit, PID=" . $pid . PHP_EOL;}$end_time = microtime(TRUE);echo sprintf("use time:%.3f s\n", $end_time - $start_time);

命令行里运行:

$ php process_t1.php  LinuxSat Apr 21 15:29:55 CST 2018rootWorker Exit, PID=672Worker Exit, PID=674Worker Exit, PID=676use time:3.080 s

大家会觉得很奇怪,为什么开了三个子进程,还是用了3秒,应该是1秒左右才对呀。

原因是父进程读取子进程返回的数据的时候,是同步阻塞读取:

echo $rec = $process->read();//同步阻塞读取管道数据 导致的后果就是父进程依次等待每个进程处理完并返回了内容,才走下一次循环。

解决方案1: 使用 swoole_event_add将管道加入到事件循环中,变为异步模式:

// echo $rec = $process->read();//同步阻塞读取管道数据//使用swoole_event_add将管道加入到事件循环中,变为异步模式swoole_event_add($process->pipe, function($pipe) use($process) {    echo $rec = $process->read();    swoole_event_del($process->pipe);//socket处理完成后,从epoll事件中移除管道});

执行结果:

Worker Exit, PID=686Worker Exit, PID=687Worker Exit, PID=688use time:1.060 sLinuxSat Apr 21 15:37:14 CST 2018root

大家会发现,use time数据并不是最后打印出来的。已经是异步的了。 实际执行时间1s左右。

解决方案2: 先不获取子进程返回值,循环结束后统一返回:

foreach ($cmds as $cmd) {    $process = new swoole_process( "my_process", true);    $process->start();    $process->write($cmd); //通过管道发数据到子进程    $process_arr[] = $process;}foreach ($process_arr as $process){    echo $rec = $process->read();}

执行结果:

LinuxSat Apr 21 15:52:24 CST 2018rootWorker Exit, PID=694Worker Exit, PID=693Worker Exit, PID=695use time:1.061 s

函数原型 swoole_process::__construct(callable $function, $redirect_stdin_stdout = false, $create_pipe= true); 第一个参数是子进程创建成功后要执行的函数。 $redirect_stdin_stdout,重定向子进程的标准输入和输出。启用此选项后,在子进程内输出内容将不是打印屏幕,而是写入到主进程管道(例如用echo打印的内容也写入管道)。读取键盘输入将变为从管道中读取数据。默认为阻塞读取。 $create_pipe,是否创建管道,启用 $redirect_stdin_stdout后,此选项将忽略用户参数,强制为true。如果子进程内没有进程间通信,可以设置为 false

注意: swoole_process在最新的1.8.0版本已经禁止在Web环境中使用了,所以也只能支持命令行。这时候如果要做并发, multi-curl是不错的选择。

进程常驻后台 如果跑的服务需要一直常驻后台,可以在 $process->start();前面加上:

swoole_process::daemon(); 服务会在后台运行。

更多示例 多进程获取网页状态码

<?php//获取多个网页信息$urls = [    'https://www.baidu.com',    'http://www.52fhy.com',    'http://www.52fhy.com/1',    'https://www.52fhy.com',];foreach ($urls as $key => $url) {    $process = new swoole_process(function(swoole_process $worker) use ($url){        $code = getHttpCode($url);        $worker->write($code);    }, true);    $process->start();    swoole_event_add($process->pipe, function($pipe) use($process, $url) {        echo sprintf("%s code: %s\n", $url, $process->read());        swoole_event_del($pipe);    });}echo "ok.\n";while($ret = swoole_process::wait()){    // echo PHP_EOL."Worker Exit, PID=" . $ret['pid'] . PHP_EOL;}/** * 获取网页http code */function getHttpCode($url){    $ch = curl_init();    curl_setopt($ch, CURLOPT_URL, $url);    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);    curl_setopt($ch, CURLOPT_HEADER, 0);//        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "HEAD");    curl_setopt($ch, CURLOPT_NOBODY, true);    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //不验证证书    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //不验证证书    curl_setopt ($ch, CURLOPT_TIMEOUT_MS, 1000);//超时时间    curl_exec($ch);    $info = curl_getinfo($ch);    curl_close($ch);    return (string)$info['http_code'];}

运行:

$ php process_get.phpok.http://www.52fhy.com code: 403http://www.52fhy.com/1 code: 404https://www.baidu.com code: 200https://www.52fhy.com code: 403

参考 1、Process https://wiki.swoole.com/wiki/page/p-process.html 2、swoole_process->read https://wiki.swoole.com/wiki/page/217.html

本文分享自微信公众号 - PHP技术大全(phpgod)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-04-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 大数据之脚踏实地学11--Spark神器的安装

    在《大数据之脚踏实地学10--Hive独立式安装》一文中我们已经介绍了Hive工具的安装流程,基于Hive可以轻松的在Hadoop集群内实现SQL语句的落地。如...

    1480
  • hadoop的单机版安装和HBase的搭建

    1. 安装jdk1.7的环境 下载hadoop. hadoop-2.5.2.tar.gz版本

    用户1499526
  • Jenkins2 学习系列8 -- 实战 使用 Generic Webhook Trigger 插件自动构建个人博客

    需求:我的博客是用hexo搭建的,每次提交完代码都需要在托管的服务器上执行手动发布命令 deploy.sh

    mafeifan
  • Shell脚本之特殊变量

    Qt君
  • Linux 一键配置网络脚本

    temp_file=temp`cat /proc/sys/kernel/random/uuid`

    Qt君
  • tomcat开机启动和服务

    说明: 这里的启动脚本可以把它分为3个部分,第一部分是申明启动脚本和注释,第二部分是定义路径的变量,第三部分是一个case...in条件选择结构。

    用户1499526
  • LINUX weblogic集群搭建- 03启动脚本的控制

    1.adminServer配置 base_domain/servers/AdminServer下新建文件夹security 同时里面创建一个新的文件boot.p...

    用户1499526
  • 通过更改页表权限增加系统调用

    实验平台i386,linux kernel版本:2..6.22(之后版本原理都是一样)

    jeff xie
  • Vue教程08(过滤器的使用)

    概念:   Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化。过滤器可以用在两个地方:mustache 插值和 v-bind 表达式。过滤器应该...

    用户4919348
  • tomcat内存配置

    1Tomcat的JVM内存溢出解决方法 在生产环境中,tomcat内存设置不好很容易出现JVM内存溢,解决方法就是修改Tomcat中的catalina.sh文...

    用户1499526

扫码关注云+社区

领取腾讯云代金券