我在做非常輕量的任務(wù)調(diào)度服務(wù)的時(shí)候剛好順帶擼了一下PHP多進(jìn)程相關(guān)的內(nèi)容,總共寫了不到300行代碼,能夠幫助理解workerman是如何進(jìn)行多進(jìn)程處理的;
已經(jīng)做了一些測(cè)試用例,把基本上常規(guī)的操作都覆蓋了,隨后還會(huì)補(bǔ)充更多的測(cè)試做覆蓋;
另外說一下,這玩意兒其實(shí)可以用在workerman/webman里,當(dāng)然這種操作比較騷(不建議,畢竟這是進(jìn)程不是線程);
可以進(jìn)行進(jìn)程的嵌套fork,當(dāng)然這種操作也比較騷,也不是很建議,還是那句話,進(jìn)程不是線程;
個(gè)人覺得代碼寫的還算是比較通俗易懂,結(jié)構(gòu)也很清晰(畢竟沒幾行代碼);
感覺其實(shí)亮哥可以用這個(gè)思路把workerman精簡(jiǎn)一下(逃
https://github.com/workbunny/process
這是一個(gè)基于ext-pcntl和ext-posix拓展的PHP多進(jìn)程助手,用于更方便的調(diào)用使用。
composer require workbunny/process
// 使用對(duì)象方式
$p = new \WorkBunny\Process\Runtime();
$p->fork(function(){
var_dump('child');
});
$p = new \WorkBunny\Process\Runtime();
$p->parent(function(){
var_dump('parent'); # 僅輸出一次
});
$p = new \WorkBunny\Process\Runtime();
$p->run(function(){
var_dump('child');
},function(){
var_dump('parent');
}, 4); # 1 + 4 進(jìn)程
$p = new \WorkBunny\Process\Runtime();
$p->wait(function(\WorkBunny\Process\Runtime $parent, int $status){
# 子進(jìn)程正常退出則會(huì)調(diào)用該方法,被調(diào)用次數(shù)是正常退出的子進(jìn)程數(shù)量
},function(\WorkBunny\Process\Runtime $parent, $status){
# 子進(jìn)程異常退出則會(huì)調(diào)用該方法,被調(diào)用次數(shù)是異常的子進(jìn)程數(shù)量
});
注:作用范圍為父Runtime的方法僅在父Runtime內(nèi)有有效響應(yīng)
方法名 | 作用范圍 | 是否產(chǎn)生分叉 | 描述 |
---|---|---|---|
fork() | 父Runtime | √ | 分叉一個(gè)子Runtime |
run() | 父Runtime | √ | 快速分叉N個(gè)子Runtime |
wait() | 父Runtime | × | 監(jiān)聽所有子Runtime狀態(tài) |
parent() | 父Runtime | × | 為父Runtime增加回調(diào)響應(yīng) |
isChild() | 所有 | × | 判斷是否是子Runtime |
getId() | 所有 | × | 獲取當(dāng)前Runtime序號(hào) |
getPid() | 所有 | × | 獲取當(dāng)前RuntimePID |
getPidMap() | 父Runtime | × | 獲取所有子RuntimePID |
number() | 父Runtime | × | 獲取Runtime數(shù)量 or 產(chǎn)生子Runtime自增序號(hào) |
setConfig() | 所有 且 分叉發(fā)生前 | × | 設(shè)置config |
getConfig() | 所有 | × | 獲取config |
getPidMap() | 父Runtime | × | 獲取所有子RuntimePID |
setPriority() | 所有 | × | 為當(dāng)前Runtime設(shè)置優(yōu)先級(jí) 需要當(dāng)前執(zhí)行用戶為super user |
getPriority() | 所有 | × | 獲取當(dāng)前Runtime優(yōu)先級(jí) |
$p = new \WorkBunny\Process\Runtime([
'pre_gc' => true,
'priority' => [
0, // 主Runtime優(yōu)先級(jí)為0
-1, // id=1的子Runtime優(yōu)先級(jí)為-1
-2, // id=2的子Runtime優(yōu)先級(jí)為-2
-3 // id=3的子Runtime優(yōu)先級(jí)為-3
]
]);
在 fork 行為發(fā)生后,Runtime對(duì)象會(huì)產(chǎn)生兩個(gè)分支
fork() 和 run() 之后的代碼域會(huì)被父子進(jìn)程同時(shí)執(zhí)行,但相互隔離:
$p = new \WorkBunny\Process\Runtime();
$p->fork(function(\WorkBunny\Process\Runtime $runtime){
var_dump($runtime->getId()); # id !== 0
});
var_dump('parent'); # 打印兩次
$p = new \WorkBunny\Process\Runtime();
$p->run(function (\WorkBunny\Process\Runtime $runtime){
},function(\WorkBunny\Process\Runtime $runtime){
}, 4);
var_dump('parent'); # 打印5次
$p = new \WorkBunny\Process\Runtime();
$p->fork(function(\WorkBunny\Process\Runtime $runtime){
var_dump($runtime->getId()); # id !== 0
var_dump('old-child');
$newP = new \WorkBunny\Process\Runtime();
$newP->fork(function(\WorkBunny\Process\Runtime $newP){
var_dump($newP->getId()); # id === 0
var_dump('new-parent');
});
});
# run 方法同理
$p = new \WorkBunny\Process\Runtime();
$p->run(function (){},function(){}, 4);
if($p->getId() === 3){
var_dump('im No. 3'); # 僅id為3的Runtime會(huì)生效
}
# fork同理
$p = new \WorkBunny\Process\Runtime();
$p->run(function (){},function(){}, 4);
if($p->isChild()){
var_dump('im child'); # 所有子Runtime都生效
}
# fork同理
$p = new \WorkBunny\Process\Runtime();
$p->run(function (){},function(){}, 4);
if(!$p->isChild()){
var_dump('im parent'); # 父Runtime都生效
}
# 或以注冊(cè)回調(diào)函數(shù)來執(zhí)行
$p->parent(function(\WorkBunny\Process\Runtime $parent){
var_dump('im parent');
});
# fork同理
$p = new \WorkBunny\Process\Runtime();
$p->fork(function(\WorkBunny\Process\Runtime $runtime){
var_dump($runtime->getId()); # id !== 0
});
$p->parent(function (\WorkBunny\Process\Runtime $runtime){
var_dump($runtime->getId()); # id === 0
});
$p->run(function (\WorkBunny\Process\Runtime $runtime){
var_dump($runtime->getId()); # id !== 0
},function(\WorkBunny\Process\Runtime $runtime){
var_dump($runtime->getId()); # id === 0
}, 4);
$p = new \WorkBunny\Process\Runtime();
$p->fork(function(\WorkBunny\Process\Runtime $runtime){
var_dump('child'); # 生效
$runtime->fork(function(){
var_dump('child-child'); # 由于fork作用范圍為父Runtime,所以不生效
});
});
$p->parent(function (\WorkBunny\Process\Runtime $runtime){
var_dump('parent'); # 生效
$runtime->fork(function(){
var_dump('parent-child'); # 生效
});
});
# run 方法同理
注:該方法僅父Runtime生效
$p = new \WorkBunny\Process\Runtime();
var_dump($p->number(false)); # 僅父Runtime會(huì)輸出
注:該方法可結(jié)合指定執(zhí)行區(qū)別獲取
$p = new \WorkBunny\Process\Runtime();
var_dump($p->getPid()); # 所有Runtime會(huì)輸出
注:該方法僅父Runtime生效
注:該方法在會(huì)阻塞至所有子Runtime退出
$p = new \WorkBunny\Process\Runtime();
$p->wait(function(\WorkBunny\Process\Runtime $runtime, $status){
# 子Runtime正常退出時(shí)
}, function(\WorkBunny\Process\Runtime $runtime, $status){
# 子Runtime異常退出時(shí)
});
??????