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 查看當前的消息隊列

這部分 下次討論

相關文章
相關標籤/搜索