爲什麼需要進程
進程是系統進行資源分配和調度的基本單位。進程作爲程序獨立運行的載體,保障程序正常執行。進程的存在使得操作系統資源的利用率大幅提升。
消息隊列
消息隊列是在消息的傳輸過程中保存消息的容器。消息隊列管理器相當於消息發送者和接收者的中介。消息隊列的主要目的是創建路由並且保證消息可靠傳遞;如果發送消息時接收者不可用,消息隊列會保留消息,直到有人接收它。
消息隊列可提供臨時存儲的功能並且能保證消息可靠的傳遞,我們正好使用它實現進程間通信。當然消息隊列不單單用於進程間通信,他的應用領域非常廣。比如消息隊列非常適用於解決消費者和生產者的問題,因爲生產者和消費者之間總會存在『速度差』。比如生產者突然少了10個,兩邊處理的速度就會不平衡,會導致排隊阻塞,服務不可用。這肯定不是我們想看到的,如果這時候引入消息隊列將兩個系統解耦,無論誰慢了都不會影響整體業務。
代碼實現
<?php
$childList = [];
$id = ftok(__FILE__,'m');//將路徑名和項目標識符轉換爲System V IPC密鑰
$msgQueue = msg_get_queue($id);//create a message queue
const MSG_TYPE = 1;
//生產者
function producer()
{
global $msgQueue;
$pid = posix_getpid();//獲取當前進程pid
$i = rand(1,10);
while ($i){
$message = "生產者進程ID:{$pid},round:{$i}";
msg_send($msgQueue,MSG_TYPE,$message);
$i--;
}
echo "producer success\n";
}
//消費者
function consume()
{
global $msgQueue;
$pid = posix_getpid();
while (msg_receive($msgQueue,MSG_TYPE,$msgType,1024,$message)){
echo "消費者進程ID:{$pid},received message:{$message}\n";
}
}
//創建進程
function createProgress($callBack){
global $childList;
//在當前進程當前位置產生分支(子進程)
$pid = pcntl_fork();
//父進程和子進程都會執行下面代碼
if ($pid == -1){
//錯誤處理:創建子進程失敗時返回-1.
exit('fork error');
}elseif ($pid == 0){
//子進程得到的$pid爲0, 所以這裏是子進程執行的邏輯。
$pid = posix_getpid();
echo "child progress:{$pid}\n";
$callBack();
exit("{$pid}:child progress exit\n");
}else{
//父進程會得到子進程號,所以這裏是父進程執行的邏輯
$childList[$pid] = 1;
}
}
createProgress('producer');
createProgress('consume');
//等待子進程中斷,防止子進程成爲殭屍進程。
if (!empty($childList)){
$pid = pcntl_wait($status);
if ($pid > 0){
unset($childList[$pid]);
echo "{$pid}\n";
}
}
運行結果
環境
- pcntl擴展:主要的進程擴展,完成進程創建於等待操作。
- sysvmsg擴展:實現system v方式的進程間通信之消息隊列。