婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > 詳解PHP多進程消費隊列

詳解PHP多進程消費隊列

熱門標簽:合肥ai電銷機器人費用 滄州電銷外呼系統價格 天津電銷外呼系統違法嗎 溫州外呼系統招商 400電話個人能不能辦理 手機外呼系統什么原理 凱立德地鐵站地圖標注 上海400客服電話怎么申請 銀行信貸電話機器人

引言

最近開發一個小功能,用到了隊列mcq,啟動一個進程消費隊列數據,后邊發現一個進程處理不過來了,又加了一個進程,過了段時間又處理不過來了......

這種方式每次都要修改crontab,如果進程掛掉了,不會及時的啟動,要等到下次crontab執行的時候才會啟動。關閉(重啟)進程的時候用的是kill,這可能會丟失正在處理的數據,比如下面這個例子,我們假設sleep過程就是處理邏輯,這里為了明顯看出效果,將處理時間放大到10s:

?php
$i = 1;
while (1) {
    echo "開始第[{$i}]次循環\n";
    sleep(10);
    echo "結束第[{$i}]次循環\n";
    $i++;
}

當我們運行腳本之后,等到循環開始之后,給進程發送kill {$pid},默認發送的是編號為15的SIGTERM信號。假設$i是從隊列拿到的,拿到2的時候,正在處理,我們給程序發送了kill信號,和隊列數據丟失一樣,問題比較大,因此我要想辦法解決這些問題。

開始第[1]次循環

結束第[1]次循環

開始第[2]次循環

[1]    28372 terminated  php t.php

nginx進程模型

這時候我想到了nginx,nginx作為高性能服務器的中流砥柱,為成千上萬的企業和個人服務,他的進程模型比較經典,如下所示:

管理員通過master進程和nginx進行交互,從/path/to/nginx.pid讀取nginx master進程的pid,發送信號給master進程,master根據不同的信號做出不同的處理,然后反饋信息給管理員。worker是master進程fork出來的,master負責管理worker,不會去處理業務,worker才是具體業務的處理者,master可以控制worker的退出、啟動,當worker意外退出,master會收到子進程退出的消息,也會重新啟動新的worker進程補充上來,不讓業務處理受影響。nginx還可以平滑退出,不丟失任何一個正在處理的數據,更新配置時nginx可以做到不影響線上服務來加載新的配置,這在請求量很大的時候特別有用。

進程設計

看了nginx的進模型,我們完全可以開發一個類似的類庫來滿足處理mcq數據的需求,做到單文件控制所有進程、可以平滑退出、可以查看子進程狀態。不需要太復雜,因為我們處理隊列數據接收一定的延遲,做到nginx那樣不間斷服務比較麻煩,費時費力,意義不是很大。設計的進程模型跟nginx類似,更像是nginx的簡化版本。

進程信號量設計

信號量是進程間通訊的一種方式,比較簡單,單功能也比較弱,只能發送信號給進程,進程根據信號做出不同的處理。

master進程啟動的時候保存pid到文件/path/to/daeminze.pid,管理員通過信號和master進程通訊,master進程安裝3種信號,碰到不同的信號,做出不同的處理,如下所示:

SIGINT => 平滑退出,處理完正在處理的數據再退出

SIGTERM => 暴力退出,無論進程是否正在處理數據直接退出

SIGUSR1 => 查看進程狀態,查看進程占用內存,運行時間等信息

master進程通過信號和worker進程通訊,worker進程安裝了2個信號,如下所示:

SIGINT => 平滑退出

SIGUSR1 => 查看worker進程自身狀態

為什么worker進程只安裝2個信號呢,少了個SIGTERM,因為master進程收到信號SIGTERM之后,向worker進程發送SIGKILL信號,默認強制關閉進程即可。

worker進程是通過master進程fork出來的,這樣master進程可以通過pcntl_wait來等待子進程退出事件,當有子進程退出的時候返回子進程pid,做處理并啟動新的進程補充上來。

master進程也通過pcntl_wait來等待接收信號,當有信號到達的時候,會返回-1,這個地方還有些坑,在下文中會詳細講。

PHP中有2種信號觸發的方式,第一種方式是declare(ticks = 1);,這種效率不高,Zend每執行一次低級語句,都會去檢查進程中是否有未處理的信號,現在已經很少使用了,PHP 5.3.0及之前的版本可能會用到這個。

第二種是通過pcntl_signal_dispatch來調用未處理的信號,PHP 5.4.0及之后的版本適用,可以巧妙的將該函數放在循環中,性能上基本沒什么損失,現在推薦適用。

PHP安裝修信號量

PHP通過pcntl_signal安裝信號,函數聲明如下所示:

bool pcntl_signal ( int $signo , [callback $handler [, bool $restart_syscalls = true ] )

第三個參數restart_syscalls不太好理解,找了很多資料,也沒太查明白,經過試驗發現,這個參數對pcntl_wait函數接收信號有影響,當設置為缺省值true的時候,發送信號,進程用pcntl_wait收不到,必須設置為false才可以,看看下面這個例子:

?php
$i = 0;
while ($i5) {
    $pid = pcntl_fork();
    $random = rand(10, 50);
    if ($pid == 0) {
        sleep($random);
        exit();
    }
    echo "child {$pid} sleep {$random}\n";
    $i++;
}

pcntl_signal(SIGINT,  function($signo) {
     echo "Ctrl + C\n";
});

while (1) {
    $pid = pcntl_wait($status);
    var_dump($pid);
    pcntl_signal_dispatch();
}

運行之后,我們對父進程發送kill -SIGINT {$pid}信號,發現pcntl_wait沒有反應,等到有子進程退出的時候,發送過的SIGINT會一個個執行,比如下面結果:

child 29643 sleep 48

child 29644 sleep 24

child 29645 sleep 37

child 29646 sleep 20

child 29647 sleep 31

int(29643)

Ctrl + C

Ctrl + C

Ctrl + C

Ctrl + C

int(29646)

這是運行腳本之后馬上給父進程發送了四次SIGINT信號,等到一個子進程推出的時候,所有信號都會觸發。

但當把安裝信號的第三個參數設置為false:

pcntl_signal(SIGINT,  function($signo) {
     echo "Ctrl + C\n";
}, false);

這時候給父進程發送SIGINT信號,pcntl_wait會馬上返回-1,信號對應的事件也會觸發。

所以第三個參數大概意思就是,是否重新注冊此信號,如果為false只注冊一次,觸發之后就返回,pcntl_wait就能收到消息,如果為true,會重復注冊,不會返回,pcntl_wait收不到消息。

信號量和系統調用

信號量會打斷系統調用,讓系統調用立刻返回,比如sleep,當進程正在sleep的時候,收到信號,sleep會馬上返回剩余sleep秒數,比如:

?php
pcntl_signal(SIGINT,  function($signo) {
     echo "Ctrl + C\n";
}, false);

while (true) {
	pcntl_signal_dispatch();
    echo "123\n";
    $limit = sleep(2);
	echo "limit sleep [{$limit}] s\n";
}

運行之后,按Ctrl + C,結果如下所示:

123

^Climit sleep [1] s

Ctrl + C

123

limit sleep [0] s

123

^Climit sleep [1] s

Ctrl + C

123

^Climit sleep [2] s

daemon(守護)進程

這種進程一般設計為daemon進程,不受終端控制,不與終端交互,長時間運行在后臺,而對于一個進程,我們可以通過下面幾個步驟把他升級為一個標準的daemon進程:

protected function daemonize()
{
    $pid = pcntl_fork();
    if (-1 == $pid) {
        throw new Exception("fork進程失敗");
    } elseif ($pid != 0) {
        exit(0);
    }
    if (-1 == posix_setsid()) {
        throw new Exception("新建立session會話失敗");
    }

    $pid = pcntl_fork();
    if (-1 == $pid) {
        throw new Exception("fork進程失敗");
    } else if($pid != 0) {
        exit(0);
    }

    umask(0);
    chdir("/");
}

攏共分五步:

1.fork子進程,父進程退出。

2.設置子進程為會話組長,進程組長。

3.再次fork,父進程退出,子進程繼續運行。

4.恢復文件掩碼為0。

5.切換當前目錄到根目錄/。

第2步是為第1步做準備,設置進程為會話組長,必要條件是進程非進程組長,因此做第一次fork,進程組長(父進程)退出,子進程通過posix_setsid()設置為會話組長,同時也為進程組長。

第3步是為了不讓進程重新控制終端,因為一個進程控制一個終端的必要條件是會話組長(pid=sid)。

第4步是為了恢復默認的文件掩碼,避免之前做的操作對文件掩碼做了設置,帶來不必要的麻煩。關于文件掩碼, linux中,文件掩碼在創建文件、文件夾的時候會用到,文件的默認權限為666,文件夾為777,創建文件(夾)的時候會用默認值減去掩碼的值作為創建文件(夾)的最終值,比如掩碼022下創建文件666 - 222 = 644,創建文件夾777 - 022 = 755:

掩碼 新建文件權限 新建文件夾權限
umask(0) 666 (-rw-rw-rw-) 777 (drwxrwxrwx)
umask(022) 644 (-rw-r--r--) 755 (drwxr-xr-x)

第5步是切換了當前目錄到根目錄/,網上說避免起始運行他的目錄不能被正確卸載,這個不是太了解。

對應5步,每一步的各種id變化信息:

操作后 pid ppid pgid sid
開始 17723 31381 17723 31381
第一次fork 17723 1 17723 31381
posix_setsid() 17740 1 17740 17740
第二次fork 17840 1 17740 17740

另外,會話、進程組、進程的關系如下圖所示,這張圖有助于更好的理解。

至此,你也可以輕松地造出一個daemon進程了。

命令設計

我準備給這個類庫設計6個命令,如下所示:

1.start 啟動命令

2.restart 強制重啟

3.stop 平滑停止

4.reload 平滑重啟

5.quit 強制停止

6.status 查看進程狀態

啟動命令

啟動命令就是默認的流程,按照默認流程走就是啟動命令,啟動命令會檢測pid文件中是否已經有pid,pid對應的進程是否健康,是否需要重新啟動。

強制停止命令

管理員通過入口文件結合pid給master進程發送SIGTERM信號,master進程給所有子進程發送SIGKILL信號,等待所有worker進程退出后,master進程也退出。

強制重啟命令

強制停止命令+啟動命令

平滑停止命令

平滑停止命令,管理員給master進程發送SIGINT信號,master進程給所有子進程發送SIGINT,worker進程將自身狀態標記為stoping,當worker進程下次循環的時候會根據stoping決定停止,不在接收新的數據,等所有worker進程退出之后,master進程也退出。

平滑重啟命令

平滑停止命令+啟動命令

查看進程狀態

查看進程狀態這個借鑒了workerman的思路,管理員給master進程發送SIGUSR1信號,告訴主進程,我要看所有進程的信息,master進程,master進程將自身的進程信息寫入配置好的文件路徑A中,然后發送SIGUSR1,告訴worker進程把自己的信息也寫入文件A中,由于這個過程是異步的,不知道worker進程啥時候寫完,所以master進程在此處等待,等所有worker進程都寫入文件之后,格式化所有的信息輸出,最后輸出的內容如下所示:

➜/dir /usr/local/bin/php DaemonMcn.php status

Daemon [DaemonMcn] 信息:

-------------------------------- master進程狀態 --------------------------------

pid       占用內存       處理次數       開始時間                 運行時間

16343     0.75M          --             2018-05-15 09:42:45      0 天 0 時 3 分

12 slaver

-------------------------------- slaver進程狀態 --------------------------------

任務task-mcq:

16345     0.75M          236            2018-05-15 09:42:45      0 天 0 時 3 分

16346     0.75M          236            2018-05-15 09:42:45      0 天 0 時 3 分

--------------------------------------------------------------------------------

任務test-mcq:

16348     0.75M          49             2018-05-15 09:42:45      0 天 0 時 3 分

16350     0.75M          49             2018-05-15 09:42:45      0 天 0 時 3 分

16358     0.75M          49             2018-05-15 09:42:45      0 天 0 時 3 分

16449     0.75M          1              2018-05-15 09:46:40      0 天 0 時 0 分

--------------------------------------------------------------------------------

等待worker進程將進程信息寫入文件的時候,這個地方用了個比較trick的方法,每個worker進程輸出一行信息,統計文件的行數,達到worker進程的行數之后表示所有worker進程都將信息寫入完畢,否則,每個1s檢測一次。

以上就是詳解PHP多進程消費隊列的詳細內容,更多關于PHP多進程消費隊列的資料請關注腳本之家其它相關文章!

您可能感興趣的文章:
  • php多進程中的阻塞與非阻塞操作實例分析
  • php多進程并發編程防止出現僵尸進程的方法分析
  • php 的多進程操作實踐案例分析
  • php 多進程編程父進程的阻塞與非阻塞實例分析
  • php實現的簡單多進程服務器類完整示例
  • PHP多進程簡單實例小結
  • PHP 多進程與信號中斷實現多任務常駐內存管理實例方法
  • php swoole多進程/多線程用法示例【基于php7nts版】
  • PHP基于swoole多進程操作示例

標簽:酒泉 白城 金華 赤峰 溫州 怒江 洛陽 七臺河

巨人網絡通訊聲明:本文標題《詳解PHP多進程消費隊列》,本文關鍵詞  詳解,PHP,多,進程,消費,隊列,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《詳解PHP多進程消費隊列》相關的同類信息!
  • 本頁收集關于詳解PHP多進程消費隊列的相關信息資訊供網民參考!
  • 推薦文章

    上一篇:詳解PHP解決守護進程Redis假死

    下一篇:Fatal error: 'break' not in the 'loop' or 'switch' context in Function.php

    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    欧美一区二区成人| 一本色道亚洲精品aⅴ| 一区二区三区欧美日韩| 久久久电影一区二区三区| 亚洲精品一区二区三区99| 制服.丝袜.亚洲.中文.综合| 在线成人av网站| 一本到三区不卡视频| 欧美日韩国产精选| 欧美三级三级三级| 欧美日韩国产免费| 日韩一区二区在线看片| 91精品国产一区二区三区香蕉| 91精品国产日韩91久久久久久| 欧美日韩精品福利| 日韩一卡二卡三卡四卡| 久久久久久久综合| 最新国产の精品合集bt伙计| 亚洲一二三四久久| 天堂资源在线中文精品| 国产一区在线观看麻豆| 成人不卡免费av| 欧美影视一区二区三区| 制服丝袜成人动漫| 国产欧美日韩亚州综合| 一区av在线播放| 麻豆国产精品官网| a级精品国产片在线观看| 欧美无乱码久久久免费午夜一区| 日韩视频永久免费| 国产精品国产精品国产专区不片| 亚洲www啪成人一区二区麻豆| 久久国产剧场电影| 91美女在线观看| 日韩午夜激情电影| 亚洲人亚洲人成电影网站色| 美女在线视频一区| 91影院在线免费观看| 日韩久久免费av| 一区二区三区小说| 国产很黄免费观看久久| 欧美日韩亚洲综合在线 | 欧美最新大片在线看| 精品国产乱码久久久久久图片| 国产精品乱人伦中文| 蜜臀av性久久久久蜜臀av麻豆 | 自拍偷拍亚洲欧美日韩| 日本不卡视频一二三区| 99久久夜色精品国产网站| 日韩欧美中文字幕一区| 亚洲视频免费观看| 国产精品白丝jk白祙喷水网站| 欧美伊人久久久久久久久影院| 日本一区二区三区在线观看| 蜜芽一区二区三区| 欧美日韩色综合| 一区二区视频在线看| 风间由美一区二区av101| 91精品视频网| 亚洲自拍偷拍麻豆| 91视频在线观看免费| 欧美激情综合五月色丁香| 免费高清成人在线| 欧美精品一二三| 一区二区三区丝袜| 色综合天天综合网天天狠天天| 欧美激情一区在线观看| 欧美肥胖老妇做爰| 亚洲免费在线观看视频| 91在线观看美女| 中文字幕一区三区| 99视频在线精品| 国产精品久久毛片| 成人精品小蝌蚪| 中文字幕中文在线不卡住| 粉嫩高潮美女一区二区三区| 久久久久久9999| 国产一区三区三区| 国产喂奶挤奶一区二区三区| 国产成人在线电影| 欧美精彩视频一区二区三区| 国产福利一区二区| 欧美高清在线一区| 91在线一区二区三区| 亚洲乱码国产乱码精品精小说 | 日韩久久久精品| 老司机精品视频导航| 精品久久国产97色综合| 激情小说欧美图片| 中文字幕va一区二区三区| 99久久精品国产观看| 亚洲美女少妇撒尿| 日韩一区二区三| 国产91精品一区二区麻豆网站| 国产精品看片你懂得| 在线日韩av片| 久久精品国产精品青草| 国产精品污www在线观看| 在线观看亚洲专区| 蜜桃视频在线观看一区二区| 久久久精品蜜桃| 一本久久a久久精品亚洲| 日韩av网站在线观看| 久久久久久免费| 91官网在线免费观看| 麻豆一区二区三区| 成人欧美一区二区三区视频网页| 欧美视频一区二区| 国产成人在线视频免费播放| 亚洲国产一区二区视频| 国产亚洲精品aa| 欧美日韩精品欧美日韩精品| 国产精品69久久久久水密桃| 亚洲一区二区三区美女| 久久综合999| 欧美色综合网站| 成人免费视频视频在线观看免费| 亚洲h动漫在线| 国产日韩欧美精品电影三级在线 | 美女网站一区二区| 国产精品久久久久aaaa| 日韩欧美国产三级| 欧美影视一区在线| 成人黄色a**站在线观看| 人人爽香蕉精品| 一区二区三区在线影院| 视频一区二区欧美| 亚洲黄色尤物视频| 国产精品视频看| www久久精品| 欧美日韩三级视频| 91福利国产精品| av在线一区二区三区| 精品亚洲欧美一区| 偷拍自拍另类欧美| 亚洲视频综合在线| 国产精品欧美经典| 国产精品网友自拍| 欧美xxxxx牲另类人与| 欧美日韩成人激情| 91久久香蕉国产日韩欧美9色| 懂色av一区二区夜夜嗨| 国产乱一区二区| 久久电影网站中文字幕| 美女诱惑一区二区| 麻豆免费精品视频| 久久精品国内一区二区三区| 亚洲高清中文字幕| 亚洲线精品一区二区三区 | 91精品国产综合久久久久久| av不卡在线观看| 成人av片在线观看| av一本久道久久综合久久鬼色| 国产成人在线免费观看| 国产精品香蕉一区二区三区| 国产精品白丝av| 国产麻豆一精品一av一免费| 国产精品亚洲第一| 成人高清av在线| 91网站最新网址| 欧美特级限制片免费在线观看| 91影院在线免费观看| 在线日韩一区二区| 欧美一区二区在线看| 精品欧美一区二区三区精品久久| 欧美不卡激情三级在线观看| 久久久久久久电影| 自拍偷拍亚洲欧美日韩| 亚洲国产精品影院| 日韩成人免费在线| 国产.欧美.日韩| jizz一区二区| 在线综合+亚洲+欧美中文字幕| 2欧美一区二区三区在线观看视频 337p粉嫩大胆噜噜噜噜噜91av | 成人国产精品视频| 欧美午夜不卡在线观看免费| 欧美巨大另类极品videosbest| 精品日产卡一卡二卡麻豆| 国产日产欧产精品推荐色| 亚洲欧美日韩系列| 日本免费新一区视频| 国产成人自拍在线| 欧美日韩精品福利| 欧美国产乱子伦| 亚洲成人av中文| 国产高清久久久| 91麻豆精品国产自产在线| 久久午夜羞羞影院免费观看| 一区二区三区色| 国产精品一级在线| 欧美视频在线观看一区二区| 久久精品一区八戒影视| 天涯成人国产亚洲精品一区av| 国产精品99久| 欧美一区二区三区小说| 国产精品亲子伦对白| 色香蕉成人二区免费| 日韩欧美精品三级| 一区av在线播放| 成人一区二区视频|