swoole教程第一节:进程管理模块(Process)-上

进程管理模块


介绍看这里 swoole的process
你们能够先看看本身的swoole版本,在命令行里面敲php

php --ri swoolehtml

更多的php命令行使用,你们学习 php命令行参数
ok 咱们直奔主题
怎么用数组

多进程的建立

很少说,直接上代码缓存

<?php
$worker_num =2;//建立的进程数
for($i=0;$i<$worker_num ; $i++){
    $process = new swoole_process('callback_function_we_write');
    $pid = $process->start();
    echo PHP_EOL . $pid;//
}
function callback_function_we_write(swoole_process $worker){
    echo  PHP_EOL;
    var_dump($worker);
    echo  PHP_EOL;
}

运行结果以下swoole

5445
object(swoole_process)#1 (3) {
  ["pipe"]=>
  int(3)
  ["callback"]=>
  string(26) "callback_function_we_write"
  ["pid"]=>
  int(5445)
}


5446
object(swoole_process)#2 (3) {
  ["pipe"]=>
  int(5)
  ["callback"]=>
  string(26) "callback_function_we_write"
  ["pid"]=>
  int(5446)
}

能够看到,咱们使用 new swoole_process 建立进程,这里须要一个参数,也就是回调函数
当咱们使用 $process->start()执行后,返回这个进程的pid ,也就是 $pid.
此时子进程启动,调用回调函数,并传一个参数 也就是 swoole_process 类型的 $worker
我故意输出了 $worker 看看里面有什么,结果有三个属性函数

pipe 进程的管道id 这个等说道进程间通讯的时候再聊
pid 就是当前子进程的 pid 啦
callback 这个是咱们本身写的回调函数名学习

到这里,咱们就能够用多进程玩耍了,
好比,咱们能够测试多进程的运行速度测试

<?php
echo PHP_EOL . time() ;
$worker_num =3;//建立的进程数
for($i=0;$i<$worker_num ; $i++){
    $process = new swoole_process('callback_function_we_write');
    $pid = $process->start();
}

function callback_function_we_write(swoole_process $worker){
    for($i=0;$i<100000000;$i++){}
    echo PHP_EOL . time() ; 
}

我本机运行结果this

1435563435 // 开始时间
1435563438 //进程1 结束时间
1435563440 //进程2 结束时间
1435563440 //进程3 结束时间命令行

算三次 用了5s (其实通常是4s)

再玩一次

<?php
echo PHP_EOL . time() ;
for($i=0;$i<100000000;$i++){}
for($i=0;$i<100000000;$i++){}
for($i=0;$i<100000000;$i++){}
echo PHP_EOL . time() ;

我本机运行结果

1435563704
1435563712

此次用了8s

作了这些,我想说明一个问题

并非说 单进程 要花8s 作完的活,咱们用3个进程就能将时间缩小三倍了

嘛,由于这是我之前的误区

多进程还能够这样玩

<?php
$funcMap=array('methodOne' , 'methodTwo' ,'methodThree' );
$worker_num =3;//建立的进程数

for($i=0;$i<$worker_num ; $i++){
    $process = new swoole_process($funcMap[$i]);
    $pid = $process->start();
    sleep(2);
}

 while(1){
            $ret = swoole_process::wait();
            if ($ret){// $ret 是个数组 code是进程退出状态码,
                $pid = $ret['pid'];
                echo PHP_EOL."Worker Exit, PID=" . $pid . PHP_EOL;
            }else{
                break;
            }
}

function methodOne(swoole_process $worker){// 第一个处理
    echo $worker->callback .PHP_EOL;
}

function methodTwo(swoole_process $worker){// 第二个处理
    echo $worker->callback .PHP_EOL;
}

function methodThree(swoole_process $worker){// 第三个处理
    echo $worker->callback .PHP_EOL;
}

我多加的sleep是为了运行时看得更清楚,你也能够去掉
这里我使用了 swoole_process::wait() 详解
目的是当子进程结束后,主进程可以知道。

咱们来想一个情景
过节了,妈妈要作饭,一看厨房里缺了 油,盐,糖,味精,十三香。因而吩咐儿子去小卖部买点回来。厨房这边也不能闲着,老妈要继续洗菜,切菜。等到调料买回来了,菜也洗好,切好了,开始炒,这边炒好了一个菜,就要马上送到餐桌上。

这个情景里面,显然使用了多进程,而且各进程作的不是一样的事情。当子进程都完成了,主进程开始继续业务。

如今有了一个问题,就拿上面的情景来讲,儿子去买调味料,若是发现盐没有了,或者钱不够了怎么办,如何与妈妈联系呢? 这就是下面要说的 进程间的通讯

进程间的通讯

Process 的通讯方式有两种

管道
swoole_process->write(string $data);
swoole_process->read(int $buffer_size=8192);

消息队列
swoole_process->useQueue();
swoole_process->push(string $data);
swoole_process->pop(int $maxsize = 8192);

咱们先说说管道

管道通信

这里咱们要再次的说起进程的建立 new swoole_process
你们请看这里 进程的建立
第一个参数是回调函数,不说了
第二个参数含义等会我会结合例子来讲
第三个参数是默认的 true,意思是建立管道,你们还记得回调函数里我特地将$worker输出看到的内容吗?

object(swoole_process)#1 (3) {
  ["pipe"]=>
  int(3)
  ["callback"]=>
  string(26) "callback_function_we_write"
  ["pid"]=>
  int(5445)
}

关键是这里的 pipe 这个就是本进程的管道id
咱们能够这样理解

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

ok,咱们看看代码

<?php
$redirect_stdout = false;// 重定向输出  ; 这个参数用途等会咱们看效果
$worker_num = 2;//进程数量
$workers = [];//存放进程用的
for($i = 0; $i < $worker_num; $i++){
    $process = new swoole_process('workerFunc',$redirect_stdout );
    $pid = $process->start();
    $workers[$pid] = $process;//将每个进程的句柄存起来
}
// 这里是主进程哦。
foreach($workers as $pid => $process){// $process 是子进程的句柄
    $process->write("hello worker[$pid]\n");//子进程句柄向本身管道里写内容                  $process->write($data);
    echo "From Worker: ".$process->read();//子进程句柄从本身的管道里面读取信息    $process->read();
    echo PHP_EOL.PHP_EOL;
 }

function workerFunc(swoole_process $worker){//这里是子进程哦
    $recv = $worker->read();
    echo PHP_EOL. "From Master: $recv\n";
    //send data to master
    $worker->write("hello master , this pipe  is ". $worker->pipe .";  this  pid  is ".$worker->pid."\n");
    sleep(2);
    $worker->exit(0);
}

贴上运行结果

From Master: hello worker[8205]

From Worker: hello master , this pipe  is 3;  this  pid  is 8205



From Master: hello worker[8206]

From Worker: hello master , this pipe  is 5;  this  pid  is 8206

喔,通信是这样的。
首先 将全部的子进程的句柄都存到 主进程的一个数组里,数组下标就是pid。
当主进程想和哪一个进程通信,就使用那个句柄向对应管道里面 写/读 数据,这样就实现了进程间的通信。

接着,咱们稍微改一下,看看运行效果

$redirect_stdout = true;// 重定向输出  注意 此次我改为 true 了,其余没变
$worker_num = 2;//进程数量
$workers = [];//存放进程用的
for($i = 0; $i < $worker_num; $i++){
    $process = new swoole_process('workerFunc',$redirect_stdout );
    $pid = $process->start();
    $workers[$pid] = $process;//将每个进程的句柄存起来
}

// 这里是主进程哦。
foreach($workers as $pid => $process){// $process 是子进程的句柄
    $process->write("hello worker[$pid]\n");//子进程句柄向本身管道里写内容                $process->write($data);
    echo "From Worker: ".$process->read();//子进程句柄从本身的管道里面读取信息    $process->read();
    echo PHP_EOL.PHP_EOL;
 }

function workerFunc(swoole_process $worker){//这里是子进程哦
    $recv = $worker->read();
    echo PHP_EOL. "From Master: $recv\n";
    //send data to master
    $worker->write("hello master , this pipe  is ". $worker->pipe .";  this  pid  is ".$worker->pid."\n");
    sleep(2);
    $worker->exit(0);
}

输出结果

From Worker: 
From Master: hello worker[8007]



From Worker: 
From Master: hello worker[8008]

诶,不同了有没有。咱们再看看建立进程时第二个参数的说明

$redirect_stdin_stdout,重定向子进程的标准输入和输出。 启用此选项后,在进程内echo将不是打印屏幕,而是写入到管道。读取键盘输入将变为从管道中读取数据。 默认为阻塞读取。

我来讲明一下,由于建立的时候指定了true,子进程中echo的内容就到了管道里面,而不是打印在屏幕上(这一点相似于php的ob缓存机制,你们想象一下)
前面说了,进程的通信是经过从管道里面读/写数据实现的,而 子进程 里 echo 的内容被 重定向到管道里面了,因此,主进程从管道里读到的内容,就是 子进程中 echo 的 内容。
也就形成了上面的 输出结果。

消息队列

我先来个连接 利用PHP操做Linux消息队列完成进程间通讯
重点是这个文章里面的两个连接文章啊,你们等会看看
还有一个命令

ipcs -q 查看当前的消息队列

这部分 下次讨论

相关文章
相关标签/搜索