PHP進程間通信的幾種方法詳解
管道通信PIPE
管道用于承載簡稱之間的通訊數(shù)據(jù)。為了方便理解,可以將管道比作文件,進程A將數(shù)據(jù)寫到管道P中,然后進程B從管道P中讀取數(shù)據(jù)。php提供的管道操作API與操作文件的API基本一樣,除了創(chuàng)建管道使用posix_mkfifo函數(shù),讀寫等操作均與文件操作函數(shù)相同。當(dāng)然,你可以直接使用文件模擬管道,但是那樣無法使用管道的特性了。
通過管道通信的大概思路是,首先創(chuàng)建一個管道,然后子進程向管道中寫入信息,父進程從管道中讀取信息,這樣就可以做到父子進程直接實現(xiàn)通信了。
<?php
// 創(chuàng)建管道
$pipePath = "pipe";
if( !file_exists( $pipePath ) ){
if( !posix_mkfifo( $pipePath, 0666) ){
exit('make pipe false!' . PHP_EOL);
}
}
// 創(chuàng)建進程,子進程寫管道,父進程讀管道
// 通過 pcntl_fork函數(shù)創(chuàng)建一個子進程。
// pcntl_fork 函數(shù) 很特殊,它調(diào)用一次擁有 多個返回值。
// 在父進程中:它返回 子進程的ID 這個值是 大于0 的。
// 在子進程中,它返回0。當(dāng)返回 -1 時表示創(chuàng)建進程失敗。
$pid = pcntl_fork();
if( $pid == 0 ){
// 子進程寫管道
$file = fopen( $pipePath, 'w');
fwrite( $file, 'hello world');
sleep(1);
exit;
}else{
// 父進程讀管道
$file = fopen( $pipePath, 'r');
// 設(shè)置成讀取非阻塞
// 當(dāng)讀取是非阻塞的情況下,父進程進行讀取信息的時候不會等待,
// 管道中沒有消息也會立馬返回。
// stream_set_blocking( $file, False);
echo fread( $file, 20) . PHP_EOL;
pcntl_wait($status); // 回收子進程
}消息隊列
消息隊列是存放在內(nèi)存中的一種隊列數(shù)據(jù)結(jié)構(gòu)。
<?php
// 獲取父進程id
$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
$childList = array();
// 創(chuàng)建消息隊列,定義消息類型
$id = ftok(__FILE__, 'm');
$msgQueue = msg_get_queue($id);
const MSG_TYEP = 1;
// 生產(chǎn)者
function producer()
{
global $msgQueue;
$pid = posix_getpid();
$repeatNum = 5;
for ($i = 0; $i <= $repeatNum; $i++) {
$str = "({$pid}) progress create! {$i}";
msg_send($msgQueue, MSG_TYEP, $str);
$rand = rand(1, 3);
sleep($rand);
}
}
// 消費者
function consumer()
{
global $msgQueue;
$pid = posix_getpid();
$repeatNum = 6;
for ($i = 1; $i<= $repeatNum; $i++) {
$rel = msg_receive($msgQueue, MSG_TYEP, $msgType, 1024, $message);
echo "{$message} | consumer({$pid}) destroy \n";
$rand = rand(1, 3);
sleep($rand);
}
}
function createProgress($callback)
{
$pid = pcntl_fork();
if ($pid == -1) {
// 創(chuàng)建失敗
exit("fork progresses error\n");
} elseif ($pid == 0) {
// 子進程執(zhí)行程序
$pid = posix_getpid();
$callback();
exit("({$pid})child progress end!\n");
} else {
// 父進程
return $pid;
}
}
for ($i = 0; $i < 3; $i++) {
$pid = createProgress('producer');
$childList[$pid] = 1;
echo "create producer progresses: {$pid}\n";
}
for ($i = 0; $i < 2; $i++) {
$pid = createProgress('consumer');
$childList[$pid] = 1;
echo "create consumer progresses: {$pid}\n";
}
while (!empty($childList)) {
$childPid = pcntl_wait($status);
if ($childPid > 0) {
unset($childList[$childPid]);
}
}
echo "({$parentPid})main progress end!\n";運行結(jié)果:
create producer progresses: 21432
create producer progresses: 21433
create producer progresses: 21434
create consumer progresses: 21435
(21426) progress create! 2 | consumer(21435) destroy
(21424) progress create! 1 | consumer(21436) destroy
create consumer progresses: 21436
(21426) progress create! 3 | consumer(21436) destroy
(21426) progress create! 4 | consumer(21435) destroy
(21425) progress create! 3 | consumer(21436) destroy
(21424) progress create! 2 | consumer(21435) destroy
(21426) progress create! 5 | consumer(21435) destroy
(21424) progress create! 3 | consumer(21436) destroy
(21433)child progress end!
(21425) progress create! 4 | consumer(21435) destroy
(21424) progress create! 4 | consumer(21436) destroy
(21434)child progress end!
(21424) progress create! 5 | consumer(21435) destroy
(21425) progress create! 5 | consumer(21436) destroy
(21432)child progress end!
(21435)child progress end!
(21436)child progress end!
(21431)main progress end!
信號量與共享內(nèi)存
<?php
$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
// 創(chuàng)建共享內(nèi)存,創(chuàng)建信號量,定義共享key
// ftok(文件路徑,資源標(biāo)識符) 創(chuàng)建一個IPC通信所需的id
$shm_id = ftok(__FILE__, 'm');
$shm_id = ftok(__FILE__, 's');
// shm_attach(id) 創(chuàng)建或者打開一個共享內(nèi)存
$shareMemory = shm_attach($shm_id);
// 返回一個可用戶訪問系統(tǒng)信號量的id
$signal = sem_get($shm_id);
const SHARE_KEY = 1;
// 生產(chǎn)者
function producer() {
global $shareMemory;
global $signal;
$pid = posix_getpid();
$repeatNum = 5;
for ($i = 1; $i <= $repeatNum; $i++) {
// 獲得信號量 - 阻塞進程,直到信號量被獲取到[lock鎖機制的關(guān)鍵]
sem_acquire($signal);
// 檢查某個key是否存在與共享內(nèi)存中
if (shm_has_var($shareMemory, SHARE_KEY)) {
// 獲取共享內(nèi)存中的key的值
$count = shm_get_var($shareMemory, SHARE_KEY);
$count ++;
// 為共享內(nèi)存中的key賦值
shm_put_var($shareMemory, SHARE_KEY, $count);
echo "({$pid}) count: {$count}\n";
} else {
// 初始化
shm_put_var($shareMemory, SHARE_KEY, 0);
echo "({$pid}) count: 0\n";
}
// 釋放
sem_release($signal);
}
}
function createProgress($callback) {
$pid = pcntl_fork();
if ($pid == -1) {
// 創(chuàng)建失敗
exit("fork progress error!\n");
} elseif ($pid == 0) {
// 子進程
$pid = posix_getpid();
$callback();
exit("({$pid}) child progress end!\n");
} else {
// 父進程
return $pid;
}
}
// 3個寫進程
for ($i = 0; $i < 3; $i ++) {
$pid = createProgress('producer');
$childList[$pid] = 1;
echo "create producer child progress: {$pid} \n";
}
// 等待所有子進程
while (!empty($childList)) {
$childPid = pcntl_wait($status);
if ($childPid > 0) {
unset($childList[$childPid]);
}
}
// 釋放共享內(nèi)存與信號量
shm_remove($shareMemory);
sem_remove($signal);
echo "({$parentPid}) main progress end!\n";運行結(jié)果:
使用信號量來實現(xiàn)共享內(nèi)存的鎖機制
parent progress pid:31720
create producer child progress: 31721
create producer child progress: 31722
(31721) count: 0
(31721) count: 1
(31721) count: 2
(31721) count: 3
(31721) count: 4
(31721) child progress end!
create producer child progress: 31723
(31722) count: 5
(31722) count: 6
(31722) count: 7
(31722) count: 8
(31722) count: 9
(31722) child progress end!
(31723) count: 10
(31723) count: 11
(31723) count: 12
(31723) count: 13
(31723) count: 14
(31723) child progress end!
(31720) main progress end!
無鎖情況
Warning: sem_release(): SysV semaphore 4357894312 (key 0x73048925) is not currently acquired in /Users/easyboom/www/example/信號量與共享內(nèi)存.php on line 38
以上就是PHP進程間通信的幾種方法詳解的詳細(xì)內(nèi)容,更多關(guān)于PHP進程間通信的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
php實現(xiàn)excel中rank函數(shù)功能的方法
這篇文章主要介紹了php實現(xiàn)excel中rank函數(shù)功能的方法,較為詳細(xì)的分析了rank函數(shù)的功能及具體實現(xiàn)方法,需要的朋友可以參考下2015-01-01
php+jquery編碼方面的一些心得(utf-8 gb2312)
在開發(fā)php與jquery的過程中,需要注意的一些心得,防止亂碼的出現(xiàn)。2010-10-10
php getimagesize 上傳圖片的長度和寬度檢測代碼
getimagesize — 取得圖像大小2010-05-05

