swoole-1.7.2增加了一个进程管理模块,用来替代PHP的pcntl扩展。pcntl是php新增的一个多进程扩展,用来实现多进程,但是有很多不完善的地方,swoole 就完善了这些地方,而且使得使用非常简单。

创建一个多进程

swoole创建多进程很简单:new Swoole\Process('callback_function') 就可以了。

比如我要同时创建10个进程,就for 循环10次就可以了。

for($i=0; $i<=10 ; $i++){
$process = new Swoole\Process('callback_function');
$pid = $process->start();
echo PHP_EOL . $pid;//
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

非常简单。

来个具体的例子,我们对比下普通的模式和多进程模式的时间速度区别:

多进程下并发3次,每次循环1亿次。和普通模式下。

<?php
echo time() .PHP_EOL ;
$worker_num = 3;//创建的进程数
for ($i=0; $i < $worker_num ; $i++) {
$process = new Swoole\Process('callback_function');
$pid = $process->start();
} function callback_function($worker) {
for($i=0;$i<100000000;$i++){}
echo time() .PHP_EOL;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

看下打印的时间, 算最大的时间,总共用了8秒。

➜  swoole git:(master) ✗ php test.php
1481791259 #开始时间,没有被阻塞。
➜ swoole git:(master) ✗
1481791267 #
1481791267
1481791267
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

具体的资源占用:

$ time php test.php
0.04s user
0.02s system
50% cpu
0.129 total
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

再看下普通循环模式:

<?php
echo time() .PHP_EOL;
for($i=0;$i<100000000;$i++){}
for($i=0;$i<100000000;$i++){}
for($i=0;$i<100000000;$i++){}
echo time() .PHP_EOL;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

看下打印时间,用了16秒。

1481791591
1481791607
  • 1
  • 2
  • 1
  • 2

具体的资源占用:

time php test.php
15.09s user
0.11s system
96% cpu
15.720 total
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

进程间的通信

如果是非常简单的多进程执行任务,那么进程间就不需要通讯了,实际情况下,很多业务是需要通讯的,比如,发邮件,如果自进程发送失败了,那么是要通知主进程的等等。

再看进程间通信之前,先看下 Swoole\Process 的几个参数:

Swoole\Process(mixed $function, $redirect_stdin_stdout = false, $create_pipe = true);

它有三个参数:

$function:子进程创建成功后要执行的函数

$redirect_stdin_stdout:重定向子进程的标准输入和输出。 设置为true,则在进程内echo将不是打印屏幕,而是写入到管道,读取键盘输入将变为从管道中读取数据。 默认为false,阻塞读取。

$create_pipe:是否创建管道,启用$redirect_stdin_stdout后,此选项将忽略用户参数,强制为true 如果子进程内没有进程间通信,可以设置为false。

swoole_process进程间支持3种通信方式:

  • 1、管道pipe
  • 2、消息队列
  • 3、信号

管道通信

管道通信是swoole_process默认的一种通信方式。当然我们也可以在实例化的时候通过参数来设定:

$process = new Swoole\Process('callback_function', false, true);

这样就创建了一个管道通信进程。我们打印下$process这个对象的值:

var_dump($process)

object(swoole_process)#1 (3) {
["pipe"]=>
int(2)
["callback"]=>
string(26) "callback_function"
["pid"]=>
int(4333)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

里面有个字段pipe是管道id,还有一个pid是进程id,所以:

每次创建一个进程后,就会随之创建一个管道,主进程想和哪一个进程通信,就向那个进程的管道写入/读取数据。

管道有2个方法,分别来写入数据,和读取数据。

write()  和  read()

来个例子,看下如何通过管道通信

<?php
/**
* process 管道通信
* User: yangyi
* Date: 2016/12/9
* Time: 17:10
*/ //进程数量
$worker_num = 2;
$workers = [];
for ($i = 0; $i < $worker_num; $i++) {
$process = new Swoole\Process('callback_function', false);
$pid = $process->start();
//将每一个进程的句柄存起来
$workers[$pid] = $process;
} // 主进程,通过管道给子进程发送数据
foreach ($workers as $pid => $process) { //向子进程管道里写内容:$process->write($data);
$process->write("hello worker[$pid]\n"); //从子进程管道里面读取信息:$process->read();
echo "From Worker: ".$process->read();
} //子进程执行的回调函数
function callback_function($worker){
//从主进程管道中读取
$recv = $worker->read();
echo PHP_EOL. "From Master: $recv\n";
//向主进程管道中写入数据
$worker->write("hello master , this pipe is ". $worker->pipe ."; this pid is ".$worker->pid."\n");
$worker->exit(0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

运行看下效果:

$ php process_pipe.php

From Master: hello worker[6759]

From Worker: hello master , this pipe  is 4;  this  pid  is 6759

From Master: hello worker[6760]

From Worker: hello master , this pipe  is 6;  this  pid  is 6760
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

注意 主进程和子进程中的 read() 不能一开始都读,得写反。不然管道中没数据,就会阻塞住了。

所以可以参考下面的图:

所以一般的顺序是:

master-->write()

work-->read()

work-->write()

master-->read()

这样才能有序的使用通道,才不会被阻塞。而且是一对一的,write 2 次,也要read 2次,先write先read。

第二个参数 $redirect_stdin_stdout 说,设置为 true ,子进程会将 echo 写入到主管道。我把上面的代码改一下,看下输出结果是啥。

$process = new Swoole\Process('callback_function', true, true);

紧紧改动了这一行,再看下:

//进程数量
$worker_num = 2;
$workers = [];
for ($i = 0; $i < $worker_num; $i++) {
$process = new Swoole\Process('callback_function', true);
$pid = $process->start();
//将每一个进程的句柄存起来
$workers[$pid] = $process;
} // 主进程,通过管道给子进程发送数据
foreach ($workers as $pid => $process) { //向子进程管道里写内容:$process->write($data);
$process->write("hello worker[$pid]\n"); //从子进程管道里面读取信息:$process->read();
echo "From Worker: ".$process->read();
} //子进程执行的回调函数
function callback_function($worker){ //从主进程管道中读取
$recv = $worker->read(); //这个echo 相当于在往master管道里写数据。write('From Master: hello worker[9251]')
echo "From Master: $recv\n"; //第二次写, 但是主进程没有第二次read(),所以没有被读到。
$worker->write("hello master , this pipe is ". $worker->pipe ."; this pid is ".$worker->pid."\n");
$worker->exit(0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

运行下输出结果为:

$ php test.php
From Worker: From Master: hello worker[9251] From Worker: From Master: hello worker[9252]
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

来分析下,因为$redirect_stdin_stdout为true,所以子进程中echo的内容就到了主管道里面,而不是打印在屏幕上,所以,主进程从管道里读到的内容,就是子进程中echo的内容。 
也就造成了上面的输出结果。

那么如何使子进程中的第二个write,能被主进程读到呢?很简单,在主进程中在 read() 一次就可以了:

// 主进程,通过管道给子进程发送数据
foreach ($workers as $pid => $process) { //向子进程管道里写内容:$process->write($data);
$process->write("hello worker[$pid]\n"); //从子进程管道里面读取信息:$process->read();
echo "From Worker: ".$process->read(); //第二次读
echo "From Worker: ".$process->read();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

再看下打印结果:

From Worker: From Master: hello worker[9328]

From Worker: hello master , this pipe  is 4;  this  pid  is 9328
From Worker: From Master: hello worker[9329] From Worker: hello master , this pipe is 6; this pid is 9329
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

消息队列

swoole进程通信还有第二种方式就是“消息队列”,这个消息队列其实就是Linux系统里面的msgqueue

swoole提供了2个方法,来实现消息队列的通信。

pop() 和 push() 

swoole深入学习 4. process的更多相关文章

  1. Swoole 入门学习(二)

    Swoole 入门学习 swoole 之 定时器 循环触发:swoole_timer_tick    (和js的setintval类似) 参数1:int $after_time_ms 指定时间[毫秒] ...

  2. swoole深入学习 8. 协程 转

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/yangyi2083334/article/ ...

  3. Swoole 简单学习(2)

    Swoole 简单学习(2) swoole之tcp服务器: //创建tcp服务器new swoole_server(string $host,int $port,int $mode=SWOOLE_PR ...

  4. swoole深入学习 2. tcp Server和tcp Client

    这节来学习Swoole最基础的Server和Client.会通过创建一个tcp Server来讲解. server <?php class Server { private $serv; pub ...

  5. swoole深入学习 1. swoole初始

    0. 前言 swoole在PHP圈火了这么久,从2年前我用node写socket聊天服务器的时候就火了,那时候,经常有类似的文章php+swoole完爆nodejs之类的文章来吸引眼球,先不说它的好与 ...

  6. Swoole源代码学习记录(十三)——Server模块具体解释(上)

    Swoole版本号:1.7.5-stable Github地址:https://github.com/LinkedDestiny/swoole-src-analysis 最终能够正式进入Server. ...

  7. Swoole源代码学习记录(十二)——ReactorThread模块

    Swoole版本号:1.7.5-stable Github地址:https://github.com/LinkedDestiny/swoole-src-analysis 这一章将分析Swoole的Re ...

  8. Swoole 进程管理模块 Process 之单进程的使用

    PHP 自带的 pcntl,存在很多不足,如: 没有提供进程间通信的功能: 不支持重定向标准输入和输出: 只提供了 fork 这样原始的接口,容易使用错误: Swoole\Process 提供了如下特 ...

  9. contiki学习笔记---process结构体

    process,字面意义,进程,看看它的结构 struct process { struct process *next; #if PROCESS_CONF_NO_PROCESS_NAMES #def ...

随机推荐

  1. Windows Server2008各版本区别

    Windows Server 2008 是专为强化下一代网络.应用程序和 Web 服务的功能而设计,是有史以来最先进的 Windows Server 操作系统.拥有 Windows Server 20 ...

  2. python实现监控windows服务控制开关服务

    转载自 :http://www.jb51.net/article/49106.htm #!/usr/bin/env python #-*- encoding:utf-8 -*- "" ...

  3. CentOS如何设置终端显示字符界面区域的大小

    红框内的文字本应该在上一行后方,调了stty也不行, stty size的值变化,但显示还是没变化 后来参考http://www.jb51.net/os/RedHat/522217.html 修改 / ...

  4. 安装jdk的时候为什么会有两个jre文件

    有些东西,你懂不懂其实并不太影响你干活,但有些人就是有疑惑就非得弄懂,不然浑身难受,我大概就是这种德性的.昨天安装javaSE的时候,看到jdk中有个jre文件夹,而根目录下又有个jre文件夹,非常困 ...

  5. 阿里云服务器搭建FTP

    操作系统:Windows Server 2008 R2企业版. 首先,创建一个用户组:ftpUsers,创建一个用户:ftpAdmin.并将ftpAdmin隶属于ftpUsers组 其次,需要安装ft ...

  6. 转载:Nginx是什么(1.1)《深入理解Nginx》(陶辉)

    原文:https://book.2cto.com/201304/19609.html 人们在了解新事物时,往往习惯通过类比来帮助自己理解事物的概貌.那么,我们在学习Nginx时也采用同样的方式,先来看 ...

  7. android margin--负的margin的使用

    通常情况下,如果我们想要两个控件实现重叠的效果,一般都是使用FrameLayout 或者RelativeLayout布局.其实,如果设置两个控件的margin值为负数,也能实显控件重叠的效果. 先展示 ...

  8. Python-CSS入门

    一.架构分析 页面 => div的层级结构 => 具有采用哪些功能标签显示内容 结构层 > 位置层(布局层) > 内容层 二.css引入 - 行间式 <!-- 简单直接, ...

  9. 大型NodeJS项目架构与优化

    使用场景: proxy(API冗余,跨域) vue ssr(服务端渲染) socket(大并发,通讯) 区块链(创业公司,新兴行业) 讨论什么? NodeJS异步IO原理及优化方案 NodeJS内存管 ...

  10. 前端开发必须知道的JS(一) 原型和继承

    原型和闭包是Js语言的难点,此文主要讲原型及原型实现的继承,在(二)中会讲下闭包,希望对大家有所帮助.若有疑问或不正之处,欢迎提出指正和讨论. 一. 原型与构造函数 Js所有的函数都有一个protot ...