站長資訊網
        最全最豐富的資訊網站

        一文了解PHP中的進程和進程間通信

        本篇文章帶大家了解一下PHP中的進程和進程間通信。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有所幫助。

        一文了解PHP中的進程和進程間通信

        環境

        php中的進程是以擴展的形式來完成。通過這些擴展,我們能夠很輕松的完成進程的一系列動作。

        pcntl擴展:主要的進程擴展,完成進程創建于等待操作。 posix擴展:完成posix兼容機通用api,如獲取進程id,殺死進程等。 sysvmsg擴展:實現system v方式的進程間通信之消息隊列。 sysvsem擴展:實現system v方式的信號量。 sysvshm擴展:實現system v方式的共享內存。 sockets擴展:實現socket通信。 這些擴展只能在linux/mac中使用,window下是不支持。最后建議php版本為5.5+。

        簡單的例子

        一個簡單的PHP多進程例子,該例子中,一個子進程,一個父進程。子進程輸出5次,退出程序。

        echo "parent progress pid:{$parentPid}n";  $childList = array();  $pid = pcntl_fork();  if ( $pid == -1) {      // 創建失敗      exit("fork progress error!n");  } else if ($pid == 0) {      // 子進程執行程序      $pid = posix_getpid();      $repeatNum = 5;      for ( $i = 1; $i <= $repeatNum; $i++) {          echo "({$pid})child progress is running! {$i} n";          $rand = rand(1,3);          sleep($rand);      }      exit("({$pid})child progress end!n");  } else {      // 父進程執行程序      $childList[$pid] = 1;  }  // 等待子進程結束  pcntl_wait($status); echo "({$parentPid})main progress end!";

        完美,終于創建了一個子進程,一個父進程。完了么?沒有,各個進程之間相互獨立的,沒有任何交集,使用范圍嚴重受到現在。怎么辦,哪就進程間通信(interprogress communication)唄。

        進程間通信(IPC)

        通常linux中的進程通信方式有:消息隊列、信號量、共享內存、信號、管道、socket。

        1.消息隊列

        消息隊列是存放在內存中的一個隊列。如下代碼將創建3個生產者子進程,2個消費者子進程。這5個進程將通過消息隊列通信。

        echo "parent progress pid:{$parentPid}n";$childList = array(); // 創建消息隊列,以及定義消息類型(類似于數據庫中的庫) $id = ftok(__FILE__,'m'); $msgQueue = msg_get_queue($id); const MSG_TYPE = 1; // 生產者 function producer(){     global $msgQueue;     $pid = posix_getpid();     $repeatNum = 5;     for ( $i = 1; $i <= $repeatNum; $i++) {         $str = "({$pid})progress create! {$i}";         msg_send($msgQueue,MSG_TYPE,$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_TYPE,$msgType,1024,$message);         echo "{$message} | consumer({$pid}) destroy n";         $rand = rand(1,3);         sleep($rand);     } } function createProgress($callback){     $pid = pcntl_fork();     if ( $pid == -1) {         // 創建失敗         exit("fork progress error!n");     } else if ($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"; } // 2個寫進程 for ($i = 0; $i < 2; $i ++ ) {     $pid = createProgress('consumer');     $childList[$pid] = 1;     echo "create consumer child progress: {$pid} n"; } // 等待所有子進程結束 while(!empty($childList)){     $childPid = pcntl_wait($status);     if ($childPid > 0){         unset($childList[$childPid]);     } } echo "({$parentPid})main progress end!n";

        由于消息隊列去數據是,只有一個進程能去到,所以不需要額外的鎖或信號量。

        2. 信號量與共享內存

        信號量:是系統提供的一種原子操作,一個信號量,同時只有你個進程能操作。一個進程獲得了某個信號量,就必須被該進程釋放掉。

        共享內存:是系統在內存中開辟的一塊公共的內存區域,任何一個進程都可以訪問,在同一時刻,可以有多個進程訪問該區域,為了保證數據的一致性,需要對該內存區域加鎖或信號量。

        以下,創建多個進程修改內存中的同一個值。

        echo "parent progress pid:{$parentPid}n"; $childList = array();  // 創建共享內存,創建信號量,定義共享key $shm_id = ftok(__FILE__,'m'); $sem_id = ftok(__FILE__,'s'); $shareMemory = shm_attach($shm_id); $signal = sem_get($sem_id); const SHARE_KEY = 1; // 生產者 function producer(){     global $shareMemory;     global $signal;     $pid = posix_getpid();     $repeatNum = 5;     for ( $i = 1; $i <= $repeatNum; $i++) {         // 獲得信號量         sem_acquire($signal);                  if (shm_has_var($shareMemory,SHARE_KEY)){             // 有值,加一             $count = shm_get_var($shareMemory,SHARE_KEY);             $count ++;             shm_put_var($shareMemory,SHARE_KEY,$count);             echo "({$pid}) count: {$count}n";         }else{             // 無值,初始化             shm_put_var($shareMemory,SHARE_KEY,0);             echo "({$pid}) count: 0n";         }         // 用完釋放         sem_release($signal);                  $rand = rand(1,3);         sleep($rand);     } } function createProgress($callback){     $pid = pcntl_fork();     if ( $pid == -1) {         // 創建失敗         exit("fork progress error!n");     } else if ($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]);     } } // 釋放共享內存與信號量 shm_remove($shareMemory); sem_remove($signal); echo "({$parentPid})main progress end!n";

        3.信號

        信號是一種系統調用。通常我們用的kill命令就是發送某個信號給某個進程的。具體有哪些信號可以在liunx/mac中運行kill -l查看。下面這個例子中,父進程等待5秒鐘,向子進程發送sigint信號。子進程捕獲信號,掉信號處理函數處理。

        echo "parent progress pid:{$parentPid}n";  // 定義一個信號處理函數 function sighandler($signo) {     $pid = posix_getpid();     echo "{$pid} progress,oh no ,I'm killed!n";     exit(1); }  $pid = pcntl_fork(); if ( $pid == -1) {     // 創建失敗     exit("fork progress error!n"); } else if ($pid == 0) {     // 子進程執行程序     // 注冊信號處理函數     declare(ticks=10);     pcntl_signal(SIGINT, "sighandler");     $pid = posix_getpid();     while(true){         echo "{$pid} child progress is running!n";         sleep(1);     }     exit("({$pid})child progress end!n"); }else{     // 父進程執行程序     $childList[$pid] = 1;     // 5秒后,父進程向子進程發送sigint信號.     sleep(5);     posix_kill($pid,SIGINT);     sleep(5); } echo "({$parentPid})main progress end!n";

        4.管道(有名管道)

        管道是比較常用的多進程通信手段,管道分為無名管道與有名管道,無名管道只能用于具有親緣關系的進程間通信,而有名管道可以用于同一主機上任意進程。這里只介紹有名管道。下面的例子,子進程寫入數據,父進程讀取數據。

        $pipe_path = '/data/test.pipe'; if(!file_exists($pipe_path)){     if(!posix_mkfifo($pipe_path,0664)){         exit("create pipe error!");     } } $pid = pcntl_fork(); if($pid == 0){     // 子進程,向管道寫數據     $file = fopen($pipe_path,'w');     while (true){         fwrite($file,'hello world');         $rand = rand(1,3);         sleep($rand);     }     exit('child end!'); }else{     // 父進程,從管道讀數據     $file = fopen($pipe_path,'r');     while (true){         $rel = fread($file,20);         echo "{$rel}n";         $rand = rand(1,2);         sleep($rand);     } }

        推薦學習:《PHP視頻教程》

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 人妻少妇精品久久| 在线精品视频一区二区| 欧美激情精品久久久久久| 国产精品久久久久久一区二区三区 | 国产亚洲精品线观看动态图| 国产成人精品免费久久久久| 中文字幕无码久久精品青草| 精品国产污污免费网站入口| 日本一区二区三区精品中文字幕| 精品久久久久久国产潘金莲 | 久久精品国产精品亜洲毛片| 911亚洲精品国内自产| 国产精品久久久久9999| 国产精品香港三级国产AV| 亚洲精品无码不卡在线播HE| 免费人妻精品一区二区三区| 国产精品99在线播放| 91人妻人人澡人人爽人人精品| 精品偷自拍另类在线观看丰满白嫩大屁股ass | 亚洲一日韩欧美中文字幕欧美日韩在线精品一区二 | 久久精品国产亚洲AV高清热| 亚洲视频在线精品| 三级国产精品| 久久精品国产亚洲Aⅴ蜜臀色欲| 99RE8这里有精品热视频| 国产精品成人不卡在线观看| 国产精品一久久香蕉国产线看观看| 日韩精品无码一区二区三区| 亚洲精品无码久久一线| 亚洲AV蜜桃永久无码精品| 日韩精品亚洲专区在线观看| 久久夜色精品国产| 日本精品少妇一区二区三区| 久久久精品国产Sm最大网站| 日本午夜精品理论片A级APP发布| 久久久久这里只有精品| 免费看污污的网站欧美国产精品不卡在线观看 | 国产精品自在线拍国产电影| 国产午夜精品一区二区三区小说| 国产精品国产三级国产a| 精品国产91久久久久久久a|