亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

從0到1優(yōu)雅的實(shí)現(xiàn)PHP多進(jìn)程管理

lakeside / 1704人閱讀

摘要:目的綜上所述,我的目標(biāo)就是實(shí)現(xiàn)基于模式實(shí)現(xiàn)的多進(jìn)程管理工具。備注下文中,父進(jìn)程統(tǒng)稱為子進(jìn)程統(tǒng)稱為。最后我們通過下圖來簡單的總結(jié)和描述這個多進(jìn)程實(shí)現(xiàn)的過程控制上面實(shí)現(xiàn)了多進(jìn)程和多進(jìn)程的常駐內(nèi)存,那如何去管理呢答案多進(jìn)程通信。

                       _        
                      | |       
_ __   __ _ _ __ _   _| |_ ___  
| "_  / _` | "__| | | | __/ _  
| | | | (_| | |  | |_| | || (_) |
|_| |_|\__,_|_|   \__,_|\__\___/ .TIGERB.cn
            
An object-oriented multi process manager for PHP

Version: 0.1.0
業(yè)務(wù)場景

在我們實(shí)際的業(yè)務(wù)場景中(PHP技術(shù)棧),我們可能需要定時或者近乎實(shí)時的執(zhí)行一些業(yè)務(wù)邏輯,簡單的我們可以使用unix系統(tǒng)自帶的crontab實(shí)現(xiàn)定時任務(wù),但是對于一些實(shí)時性要求比較高的業(yè)務(wù)就不適用了,所以我們就需要一個常駐內(nèi)存的任務(wù)管理工具,為了保證實(shí)時性,一方面我們讓它一直執(zhí)行任務(wù)(適當(dāng)?shù)乃撸WCcpu不被100%占用),另一方面我們實(shí)現(xiàn)多進(jìn)程保證并發(fā)的執(zhí)行任務(wù)。

目的

綜上所述,我的目標(biāo)就是:實(shí)現(xiàn)基于php-cli模式實(shí)現(xiàn)的master-worker多進(jìn)程管理工具。其次,“我有這樣一個目標(biāo),我是怎樣一步步去分析、規(guī)劃和實(shí)現(xiàn)的”,這是本文的宗旨。

備注:下文中,父進(jìn)程統(tǒng)稱為master,子進(jìn)程統(tǒng)稱為worker。
分析

我們把這一個大目標(biāo)拆成多個小目標(biāo)去逐個實(shí)現(xiàn),如下:

多進(jìn)程

目的:一個master fork多個worker

現(xiàn)象:所有worker的ppid父進(jìn)程ID為當(dāng)前master的pid

master控制worker

目的:master通知worker,worker接收來自master的消息

master接收信號

目的:master接收并自定義處理來自終端的信號

多進(jìn)程

PHP fork進(jìn)程的方法 pcntl_fork, 這個大家應(yīng)該有所了解,如果不知道的簡單google/bing一下應(yīng)該很容易找到這個函數(shù)。接著FTM, 我們看看pcntl_fork這個函數(shù)的使用方式大致如下:

$pid = pcntl_fork(); // pcntl_fork 的返回值是一個int值
                     // 如果$pid=-1 fork進(jìn)程失敗
                     // 如果$pid=0 當(dāng)前的上下文環(huán)境為worker
                     // 如果$pid>0 當(dāng)前的上下文環(huán)境為master,這個pid就是fork的worker的pid

接著看代碼:

$pid = pcntl_fork();    
switch ($pid) {
  case -1:
    // fatal error 致命錯誤 所有進(jìn)程crash掉
    break;

  case 0:
    // worker context
    exit; // 這里exit掉,避免worker繼續(xù)執(zhí)行下面的代碼而造成一些問題
    break;

  default:
    // master context
    pcntl_wait($status); // pcntl_wait會阻塞,例如直到一個子進(jìn)程exit
    // 或者 pcntl_waitpid($pid, $status, WNOHANG); // WNOHANG:即使沒有子進(jìn)程exit,也會立即返回
    break;
}

我們看到master有調(diào)用pcntl_wait或者pcntl_waitpid函數(shù),為什么呢?首先我們在這里得提到兩個概念,如下:

孤兒進(jìn)程:父進(jìn)程掛了,子進(jìn)程被pid=1的init進(jìn)程接管(wait/waitpid),直到子進(jìn)程自身生命周期結(jié)束被系統(tǒng)回收資源和父進(jìn)程采取相關(guān)的回收操作

僵尸進(jìn)程:子進(jìn)程exit退出,父進(jìn)程沒有通過wait/waitpid獲取子進(jìn)程狀態(tài),子進(jìn)程占用的進(jìn)程號等描述資源符還存在,產(chǎn)生危害:例如進(jìn)程號是有限的,無法釋放進(jìn)程號導(dǎo)致未來可能無進(jìn)程號可用

所以,pcntl_wait或者pcntl_waitpid的目的就是防止worker成為僵尸進(jìn)程(zombie process)。

除此之外我們還需要把我們的master掛起和worker掛起,我使用的的是while循環(huán),然后usleep(200000)防止CPU被100%占用。

最后我們通過下圖(1-1)來簡單的總結(jié)和描述這個多進(jìn)程實(shí)現(xiàn)的過程:

master控制worker

上面實(shí)現(xiàn)了多進(jìn)程和多進(jìn)程的常駐內(nèi)存,那master如何去管理worker呢?答案:多進(jìn)程通信。話不多說google/bing一下,以下我列舉幾種方式:

命名管道: 感興趣

隊(duì)列: 個人感覺和業(yè)務(wù)中使用redis做消息隊(duì)列思路應(yīng)該一致

共享內(nèi)存: 違背“不要通過共享內(nèi)存來通信,要通過通信來實(shí)現(xiàn)共享”原則

信號: 承載信息量少

套接字: 不熟悉

所以我選擇了“命名管道”的方式。我設(shè)計(jì)的通信流程大致如下:

step 1: 創(chuàng)建worker管道

step 2: master寫消息到worker管道

step 3: worker讀消息從worker管道

接著還是逐個擊破,當(dāng)然話不多說還是google/bing一下。posix_mkfifo創(chuàng)建命名管道、fopen打開文件(管道以文件形式存在)、fread讀取管道、fclose關(guān)閉管道就呼嘯而出,哈哈,這樣我們就能很容易的實(shí)現(xiàn)我們上面的思路的了。接著說說我在這里遇到的問題:fopen阻塞了,導(dǎo)致業(yè)務(wù)代碼無法循環(huán)執(zhí)行,一想不對啊,平常fopen普通文件不存在阻塞行為,這時候二話不說FTM搜fopen,crtl+f頁面搜“block”,重點(diǎn)來了:

fopen() will block if the file to be opened is a fifo. This is true whether it"s opened in "r" or "w" mode.  (See man 7 fifo: this is the correct, default behaviour; although Linux supports non-blocking fopen() of a fifo, PHP doesn"t).

翻譯下,大概意思就是“當(dāng)使用fopen的r或者w模式打開一個fifo的文件,就會一直阻塞;盡管linux支持非阻塞的打開fifo,但是php不支持?!?,得不到解決方案,不支持,感覺要放棄,一想這種場景應(yīng)該不會不支持吧,再去看看posix_mkfifo,結(jié)果喜出望外:



The "r+" allows fopen to return immediately regardless of external  writer channel.

結(jié)論使用“r+”,同時我們又知道了使用stream_set_blocking防止緊接著的fread阻塞。接著我們用下圖(1-2)來簡單的總結(jié)和描述這個master-worker通信的方式。

master接收信號

最后我們需要解決的問題就是master怎么接受來自client的信號,google/bing結(jié)論:

master接收信號 -> pcntl_signal注冊對應(yīng)信號的handler方法 -> pcntl_signal_dispatch() 派發(fā)信號到handler

如下圖(1-3)所示,

其他

接著我們只要實(shí)現(xiàn)不同信號下master&worker的策略,例如worker的重啟等。這里需要注意的就是,當(dāng)master接受到重啟的信號后,worker不要立即exit,而是等到worker的業(yè)務(wù)邏輯執(zhí)行完成了之后exit。具體的方式就是:

master接收reload信號 -> master把reload信號寫worker管道 -> worker讀取到reload信號 -> worker添加重啟標(biāo)志位 -> worker執(zhí)行完業(yè)務(wù)邏輯后且檢測到重啟的標(biāo)志位后exit
建模

上面梳理完我們的實(shí)現(xiàn)方式后,接著我們就開始碼代碼了。碼代碼之前進(jìn)行簡單的建模,如下:

進(jìn)程管理類Manager

- attributes
  + master: master對象
  + workers: worker進(jìn)程對象池
  + waitSignalProcessPool: 等待信號的worker池
  + startNum: 啟動進(jìn)程數(shù)量
  + userPasswd: linux用戶密碼
  + pipeDir: 管道存放路徑
  + signalSupport: 支持的信號
  + hangupLoopMicrotime: 掛起間隔睡眠時間
- method
  + welcome: 歡迎于
  + configure: 初始化配置
  + fork: forkworker方法
  + execFork: 執(zhí)行forkworker方法
  + defineSigHandler: 定義信號handler
  + registerSigHandler: 注冊信號handler
  + hangup: 掛起主進(jìn)程

進(jìn)程抽象類Process

- attributes
  + type: 進(jìn)程類型 master/worker
  + pid: 進(jìn)程ID
  + pipeName: 管道名稱 
  + pipeMode: 管道模式
  + pipeDir: 管道存放路徑
  + pipeNamePrefix: 管道名稱前綴
  + pipePath: 管道生成路徑
  + readPipeType: 讀取管道數(shù)據(jù)的字節(jié)數(shù)
  + workerExitFlag: 進(jìn)程退出標(biāo)志位
  + signal: 當(dāng)前接受到的信號
  + hangupLoopMicrotime: 掛起間隔睡眠時間
- method
  + hangup: 掛起進(jìn)程(抽象方法)
  + pipeMake: 創(chuàng)建管道
  + pipeWrite: 寫管道
  + pipeRead: 讀管道
  + clearPipe: 清理管道文件
  + stop: 進(jìn)程exit

master實(shí)體類MasterProcess

- attributes
  + 
- method
  + hangup: 掛起進(jìn)程

worker實(shí)體類MasterProcess

- attributes
  + 
- method
  + dispatchSig: 定義worker信號處理方式

最后我們需要做的就是優(yōu)雅的填充我們的代碼了。

最后

項(xiàng)目地址 https://github.com/TIGERB/naruto

個人知識還有很多不足,如果有寫的不對的地方,希望大家及時指正。

THX~

掃面下方二維碼關(guān)注我的技術(shù)公眾號,及時為大家推送我的原創(chuàng)技術(shù)分享

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/26152.html

相關(guān)文章

  • 寫給PHP程序員信號處理教程

    摘要:和內(nèi)容無關(guān)的主題什么是信號信號就是事件發(fā)生時,對進(jìn)程的一種通知機(jī)制也叫軟件中斷。當(dāng)一個進(jìn)程收到信號后,內(nèi)核會暫停該進(jìn)程正在執(zhí)行的代碼,并跳轉(zhuǎn)到對應(yīng)的信號處理函數(shù)中,如果處理函數(shù)不中斷,執(zhí)行完處理函數(shù)后,會繼續(xù)執(zhí)行之前中斷的地方往下執(zhí)行。 今天晚上吃鹵煮,領(lǐng)桌的妹子問我,這玩意兒能吃么?我:你覺得能吃就能吃。。。和內(nèi)容無關(guān)的主題 什么是信號 信號就是事件發(fā)生時,對進(jìn)程的一種通知機(jī)制(也叫...

    Bamboy 評論0 收藏0
  • 我為什么要開發(fā)一個 MixPHP 框架

    摘要:異步隊(duì)列消費(fèi)者開發(fā)只提供了模式下運(yùn)行控制器方法,并未提供主進(jìn)程多子進(jìn)程的進(jìn)程模型,并未提供多線程處理。多線程異步隊(duì)列服務(wù)只需寫好控制器方法,然后在配置文件中配置下路由命名空間進(jìn)程線程數(shù)量,就可在模式中啟動多進(jìn)程多線程模型的異步隊(duì)列處理程序。 最近業(yè)余時間一直在開發(fā)ExpressPHP的第二個版本 MixPHP,今天下班想起之前一個面試官的問題:你為什么還要再造一個輪子呢?仔細(xì)回想,第一...

    SnaiLiu 評論0 收藏0
  • PHP進(jìn)程初探 --- 信號

    摘要:第一次子進(jìn)程正在休眠中,父進(jìn)程依舊在循環(huán)中。第三次此時父進(jìn)程已經(jīng)執(zhí)行了,將已經(jīng)退出的子進(jìn)程回收,釋放了等資源。梳理一下流程,子進(jìn)程向父進(jìn)程發(fā)送信號是對人們來說是透明的,也就是說我們無須關(guān)心。 [原文地址:https://blog.ti-node.com/blog...] 上一篇尬聊了通篇的pcntl_wait()和pcntl_waitpid(),就是為了解決僵尸進(jìn)程的問題,但最后看起來...

    Prasanta 評論0 收藏0
  • 現(xiàn)代軟件開發(fā)流程-by 12-Factor

    摘要:將開發(fā)環(huán)境和生產(chǎn)環(huán)境的差異降至最低,并使用持續(xù)交付實(shí)施敏捷開發(fā)??梢栽诠ぞ呒軜?gòu)和開發(fā)流程不發(fā)生明顯變化的前提下實(shí)現(xiàn)擴(kuò)展。我們的初衷是分享在現(xiàn)代軟件開發(fā)過程中發(fā)現(xiàn)的一些系統(tǒng)性問題,并加深對這些問題的認(rèn)識。 簡介 如今,軟件通常會作為一種服務(wù)來交付,它們被稱為網(wǎng)絡(luò)應(yīng)用程序,或軟件即服務(wù)(SaaS)。12-Factor 為構(gòu)建如下的 SaaS 應(yīng)用提供了方法論: 使用標(biāo)準(zhǔn)化流程自動配置,從...

    draveness 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<