[toc]

## 进程管理

### 官网实例了解进程api

根据官方实例加上注释

* 子进程异常退出时,自动重启

* 主进程异常退出时,子进程会继续执行,完成所有任务后退出

~~~

class Process

{

// 主进程的pid

public $mpid = 0;

//

public $works = [];

// 创建多少个子进程

public $max_precess = 1;

public $new_index = 0;

public function __construct()

{

try {

// 给当前主进程命名

swoole_set_process_name(sprintf('php-ps:%s' , 'master'));

// 获得当前主进程的PID

$this->mpid = posix_getpid();

// 创建子进程并运行

$this->run();

// 运行结束后回收并重启

$this->processWait();

} catch (\Exception $e) {

die('ALL ERROR: ' . $e->getMessage());

}

}

public function run()

{

for ($i = 0;$i < $this->max_precess;$i ++) {

$this->CreateProcess();

}

}

public function CreateProcess($index = null)

{

// 创建子进程,用于在检查主进程是否还活着

$process = new \swoole_process(

function (\swoole_process $worker) use ($index){

// 设置进程名称

if (is_null($index)) {

$index = $this->new_index;

$this->new_index ++;

}

swoole_set_process_name(sprintf('php-ps:%s' , $index));

// 120秒后重启子进程

for ($j = 0;$j < 120;$j ++) {

$this->checkMpid($worker);

echo "msg: {$j}\n";

sleep(1);

}

} , false , false

);

$pid = $process->start();

$this->works[$index] = $pid;

return $pid;

}

public function checkMpid(&$worker)

{

// 检查主进程是否存在

if (!\swoole_process::kill($this->mpid , 0)) {

// 如果不存在的话就退出子进程

$worker->exit();

// 这句提示,实际是看不到的.需要写到日志中

echo "Master process exited, I [{$worker['pid']}] also quit\n";

}

}

public function rebootProcess($ret)

{

$pid = $ret['pid'];

$index = array_search($pid , $this->works);

if ($index !== false) {

$index = intval($index);

// 名称设置为一样

$new_pid = $this->CreateProcess($index);

echo "rebootProcess: {$index}={$new_pid} Done\n";

return;

}

throw new \Exception('rebootProcess Error: no pid');

}

public function processWait()

{

while (1) {

// 如果子进程存在

if (count($this->works)) {

// 等待其结束后回收

$ret = \swoole_process::wait();

if ($ret) {

// 回收成功后重启子进程

$this->rebootProcess($ret);

}

} else {

break;

}

}

}

}

~~~

使用`ps aft | grep php`查看进程关系

![](https://i.loli.net/2019/04/26/5cc29faa3e6aa.png)

### 父子进程通过管道通信

~~~

// 第二参数设为true,可以使用write和read来通过管道使父子进程通信

$process = new \swoole_process(

function (\swoole_process $process){

$process->write('Hello');

} , true

);

$process->start();

usleep(100);

// 输出 Hello

echo $process->read();

~~~

### 调用外部程序

~~~

$process = new \Swoole\Process(

function (\Swoole\Process $childProcess){

// 1. 必须写绝对路径

// 2. 参数必须分开放到数组中

$childProcess->exec(

'/usr/local/bin/php' , [

'/var/www/project/yii-best-practice/cli/yii' ,

't/index' ,

'-m=123' ,

'abc' ,

'xyz'

]);

// 3. 执行shell命令,略有区别。不过一般使用协程co:exec()

$childProcess->exec('/bin/sh' , ['-c' , "cp -rf /data/test/* /tmp/test/"]);

}

);

$process->start();

~~~

### 在SwooleServer中添加用户自定义进程

~~~

$server = new \Swoole\Server('127.0.0.1', 9501);

/**

* 自定义用户进程实现广播功能

* 循环接收管道消息,并发给服务器的所有连接

*/

$process = new \Swoole\Process(function($process) use ($server) {

// 用户进程内应当进行while(true)或EventLoop循环,否则用户进程会不停地退出重启

while (true) {

$msg = $process->read();

// 创建的子进程可以调用$server对象提供的各个方法和属性

foreach($server->connections as $conn) {

$server->send($conn, $msg);

}

}

});

// 在swooleServer中新增进程时,子进程不需要start

// 在Server启动时会自动创建进程,并执行指定的子进程函数

$server->addProcess($process);

$server->on('receive', function ($serv, $fd, $reactor_id, $data) use ($process) {

//群发收到的消息

$process->write($data);

});

$server->start();

~~~

可以参考easyswoole的编码方式:http://www.easyswoole.com/Manual/3.x/Cn/_book/BaseUsage/process.html。 把复杂的业务逻辑写进类里面,然后实例出来调用`getProcess()`

### 进程池

~~~

// 设置10个工作进程

$workerNum = 10;

$pool = new \Swoole\Process\Pool($workerNum);

// 配置事件回调

$pool->on("WorkerStart", function ($pool, $workerId) {

// 得到Process对象,可以使用Process对象的方法

$process = $pool->getProcess();

$process->exec("/bin/sh", ['-c', 'ls -l']);

});

$pool->on("WorkerStop", function ($pool, $workerId) {

echo "Worker#{$workerId} is stopped\n";

});

// 启动工作进程

$pool->start();

~~~

>[danger] 这边测试下来,`onWorkerStart`事件一直重复触发,按道理是只会在进程启动的时候执行一次。原因未知。有可能是单核虚拟机的问题。

### 进程信号异步监听

[Linux信号列表](https://wiki.swoole.com/wiki/page/p-LinuxSignal.html)

~~~

// 监听SIGTERM信号(停止)

\Swoole\Process::signal(SIGTERM, function($signo) {

echo "shutdown.";

});

~~~

![](https://i.loli.net/2019/04/26/5cc2db7825118.png)

查到当前的进程pid为19093, 然后 `kill -9 19093`, 杀掉之后就输出`shutdown.`

## 进程隔离与内存共享

进程和进程之间是隔离的。

* 不同的进程中PHP变量不是共享,即使是全局变量,在A进程内修改了它的值,在B进程内是无效的

* 如果需要在不同的Worker进程内共享数据,可以用`Redis`、`MySQL`、`文件`、`Swoole\Table`、`APCu`、`shmget`等工具实现

* 不同进程的文件句柄是隔离的,所以在A进程创建的Socket连接或打开的文件,在B进程内是无效,即使是将它的fd发送到B进程也是不可用的

~~~

$server = new \Swoole\Http\Server('0.0.0.0', 9500);

// 4个进程

$server->set([ 'worker_num' => 4]);

$i = 1;

$server->on('Request', function ($request, $response) {

global $i;

$response->end($i++);

});

$server->start();

~~~

用两个浏览器访问上面的`HttpServer`,会发现输出的$i都不一样。如果是worker设置为1的话就一样。因为`$i`变量虽然是全局变量(`global`),但由于进程隔离的原因。假设有`4`个工作进程,在`进程1`中进行`$i++`,实际上只有`进程1`中的`$i`变成`2`了,其他另外`3`个进程内`$i`变量的值还是`1`。

使用`Swoole\Table`来做到内存共享(其实更建议`redis`)

~~~

$server = new \Swoole\Http\Server('0.0.0.0', 9500);

// 4个进程

$server->set([ 'worker_num' => 4]);

// 参数指定表格的最大行数,必须为2的n次方,如果小于1024则默认成1024,即1024是最小值

// Table基于行锁,所以单次set/get/del在多线程/多进程的环境下是安全的

// set/get/del等方法是原子操作,用户代码中不需要担心数据加锁和同步的问题

$table = new \Swoole\Table(8);

// 字符串类型必须指定第三参数,如果是整型的话,注意溢出

$table->column('i',$table::TYPE_INT);

$table->create();

$table->set('table',['i' => 1]);

$server->on('Request', function ($request, $response) use($table) {

$table->incr('table','i');

$response->end($table->get('table','i'));

});

$server->start();

~~~

更多参考: https://wiki.swoole.com/wiki/page/p-table.html

>[info] 进程在系统是非常昂贵的资源,创建进程消耗很大,要谨慎使用。如果要创建的子进程业务是要长期执行的,比如“监控文件文件变化”,可以使用子进程。其它短期任务,能用协程尽量用协程。

php跨进程内存共享,进程管理与内存共享相关推荐

  1. 什么是共享汽车运营系统、共享汽车硬件系统、共享汽车管理软件、共享汽车运营管理系统研究设计

    如何编写共享汽车系统设计方案?定制共享汽车系统开发方案有哪些计划? 车辆管理系统设计方案,从各个方面进行详尽设计,包括驾驶员档案.车辆档案管理.油卡管理.车辆出车管理.车辆加油.车辆维修.车辆规费.车 ...

  2. 共享车位停车数据 共享停车管理平台,共享车位解决停车问题!

    城市车位紧张,闲置车位多,车位需求量大,车位供需失衡,高峰时段的停车需求更大, 车场车位信息闭塞,一些停车场不对外开放,车位大量闲置,使用率低,车主找不到车位,闲置车位得不到充分使用,造成资源的浪费. ...

  3. 进程线程007 进程挂靠与跨进程读写内存

    文章目录 进程挂靠 进程与线程的关系 线程与进程如何关联 为什么需要ApcState.Process CR3的值可以随便改吗 分析NtReadVirtualMemory函数 总结 跨进程读写内存 跨进 ...

  4. linux 进程原理内存,linux进程通信之共享内存原理(基于linux 1.2.13)

    1 有一个全局的结构体数据,每次需要一块共享的内存时(shmget),从里面取一个结构体,记录相关的信息. struct shmid_ds { // 权限相关 struct ipc_perm shm_ ...

  5. Android系统中的进程管理:内存的回收

    本文是Android系统进程管理的第三篇文章.进程管理的前面两篇文章,请参见这里: Android系统中的进程管理:进程的创建 Android系统中的进程管理:进程的优先级 本文适合Android平台 ...

  6. python slice是共享内存吗_python共享内存实现进程通信

    1.概述 共享内存可以说是最有用的进程间通信方式.两个不同的进程共享内存的意思是:同一块物理内存被映射到两个进程的各自的进程地址空间.一个进程可以及时看到另一个进程对共享内存的更新,反之亦然.采用共享 ...

  7. Linux 进程资源分配,linux 进程管理和内存分配

    1.进程相关概念 进程:正在运行中的程序 内核功用:进程管理.文件系统.网络功能.内存管理.驱动程序.安全功能等 Process:运行中的程序的一个副本,是被载入内存的一个指令集合 进程 ID(Pro ...

  8. [转]内存与进程管理器

    内存与进程管理器 ========================== But I fear tomorrow I'll be crying,                              ...

  9. [书]操作系统真象还原 -- 第11、12章 用户进程及调度、系统调用、内存管理

    ======  第 12 章 系统调用.内存管理 ====== GITHUB: https://github.com/trb331617/os_elephant/tree/master/chapter ...

最新文章

  1. 【项目展示】自己用C语言编写的汉诺塔小游戏
  2. 何恺明大神新作:一种用于目标检测的主流ViT架构,效果SOTA
  3. shopify api php 开发,Shopify插件开发基础篇-获取店铺信息
  4. [Issue Fixed]-repo-error: .repo/manifests/: contains uncommitted changes
  5. 在浏览器中进行深度学习:TensorFlow.js (一)基本概念
  6. (二)利用Java WebService调用天气预报实践
  7. aws部署ssh_将Quarkus应用程序部署到AWS Elastic Beanstalk
  8. PostgreSQL 摘得 DB-Engines 2020 年度数据库
  9. [HNOI2015]开店(树剖+主席树+标记永久化)
  10. [转载] 终于来了!TensorFlow 2.0入门指南(上篇)
  11. 使用 Python 构建电影推荐系统
  12. 如何解决python 画图时 it could not find or load the Qt platform plugin “windows“ in “”的问题
  13. java 回车表示_Java 换行和回车
  14. word上下的横线怎么去掉_word中去掉页面上的横线 word页面横线怎么去掉
  15. 使用C语言绘制一个笑脸smile
  16. 美国大学倒闭危机!1/4高校或将破产,清华本科留学率下降
  17. 使用百度翻译开发平台,英文翻译为中文
  18. 【ps】使用shotoshop按比例缩小图片
  19. 简单的使用一下增强for循环
  20. 教你怎样混社会[转]

热门文章

  1. 【翻译】使用PowerShell获取网站运行时数据
  2. Linux 命令(6)—— sort 命令
  3. db2中TRANSLATE函数可以实现简单的正则(不属于真正的正则表达式)
  4. 1.3计算机硬件的主要指标
  5. 开发规范 - UML图
  6. CSU 2151 集训难度(线段树)
  7. 第13条:合理利用try/expect/else/finally结构中的每个代码块
  8. node.js之第一天
  9. [译]几个步骤来删除SQL Server数据库用户
  10. [ZJOI2012]灾难(建图)