[原文地址:https://blog.ti-node.com/blog...]php
乾巴巴地叨逼叨了這麼久,時候表演真正的技術了!node
作個高端點兒的玩意吧,加入咱們要作一個任務系統,這個系統能夠在後臺幫咱們完成一大波(注意是一大波)數據的處理,那麼咱們天然想到,多開幾個進程分開處理這些數據,同時咱們不能執行了php task.php後終端掛起,萬一一不當心關閉了終端都會致使任務失敗,因此咱們還要實現程序的daemon化。好啦,開始了!數組
首先,咱們第一步就得將程序daemon化了!函數
// 設置umask爲0,這樣,當前進程建立的文件權限則爲777 umask( 0 ); $pid = pcntl_fork(); if( $pid < 0 ){ exit('fork error.'); } else if( $pid > 0 ) { // 主進程退出 exit(); } // 子進程繼續執行 // 最關鍵的一步來了,執行setsid函數! if( !posix_setsid() ){ exit('setsid error.'); } // 理論上一次fork就能夠了 // 可是,二次fork,這裏的歷史淵源是這樣的:在基於system V的系統中,經過再次fork,父進程退出,子進程繼續 // 保證造成的daemon進程絕對不會成爲會話首進程,不會擁有控制終端。 $pid = pcntl_fork(); if( $pid < 0 ){ exit('fork error'); } else if( $pid > 0 ) { // 主進程退出 exit; } // 子進程繼續執行 // 給進程從新起個名字 cli_set_process_title('php master process');
加入咱們fork出5個子進程就能夠搞定這些任務,那麼fork出5個子進程,同時父進程要負責這5個子進程的狀態等。spa
// 因爲*NIX好像並無(若是有,請告知)能夠獲取父進程fork出全部的子進程的ID們的功能,因此這個須要咱們本身來保存 $child_pid = []; // 父進程安裝SIGCHLD信號處理器並分發 pcntl_signal( SIGCHLD, function(){ // 這裏注意要使用global將child_pid全局化,否則讀到去數組將爲空,具體緣由能夠本身思考下 global $child_pid; // 若是子進程的數量大於0,也就說若是還有子進程存活未 退出,那麼執行回收 $child_pid_num = count( $child_pid ); if( $child_pid_num > 0 ){ // 循環子進程數組 foreach( $child_pid as $pid_key => $pid_item ){ $wait_result = pcntl_waitpid( $pid_item, $status, WNOHANG ); // 若是子進程被成功回收了,那麼必定要將其進程ID從child_pid中移除掉 if( $wait_result == $pid_item || -1 == $wait_result ){ unset( $child_pid[ $pid_key ] ); } } } } ); // fork出5個子進程出來,並給每一個子進程重命名 for( $i = 1; $i <= 5; $i++ ){ $_pid = pcntl_fork(); if( $_pid < 0 ){ exit(); } else if( 0 == $_pid ) { // 重命名子進程 cli_set_process_title('php worker process'); // 啦啦啦啦啦啦啦啦啦啦,請在此處編寫你的業務代碼 // do something ... // 啦啦啦啦啦啦啦啦啦啦,請在此處編寫你的業務代碼 // 子進程退出執行,必定要exit,否則就不會fork出5個而是多於5個任務進程了 exit(); } else if( $_pid > 0 ) { // 將fork出的任務進程的進程ID保存到數組中 $child_pid[] = $_pid; } } // 主進程繼續循環不斷派遣信號 while( true ){ pcntl_signal_dispatch(); // 每派遣一次休眠一秒鐘 sleep( 1 ); }
[原文地址:https://blog.ti-node.com/blog...]code