PHP中的PCNTL可以實現(xiàn)多進程編程,由于項目場景需要,試用了一下,感觸頗多,也長了不少見識,就此對遇到的問題小做一個總結,以備不時之需。
創(chuàng)新互聯(lián)公司專注于天涯企業(yè)網站建設,自適應網站建設,商城網站建設。天涯網站建設公司,為天涯等地區(qū)提供建站服務。全流程按需設計網站,專業(yè)設計,全程項目跟蹤,創(chuàng)新互聯(lián)公司專業(yè)和態(tài)度為您提供的服務
問題一:fork泛濫
我想在一個父進程中起10個子程來完成我的工作,代碼如下:
for($i = 0; $i < 10; $i++) { $pid = pcntl_fork(); if($pid == -1) { echo "Could not fork!\n"; exit(1); } if(!$pid) { //child process workspace //TODO Api::refreshCache(); } }
由于Api::refreshCache邏輯中有數(shù)據(jù)庫操作,代碼一執(zhí)行,就把DB搞死了,報了N多個too many connections。我以為是DB原本就抽風了,檢查DB,正常。
最終發(fā)現(xiàn),這一段代碼fork的可不是10個子進程,而是
20 + 21 + 22+ 23 + 24 + ... + 29 = 210-1 = 1023 個子進程。
恐怖了吧?這是因為子進程又fork子進程,并且子進程不共享父進程$i變量更新的值,由此導致數(shù)量成指數(shù)關系增長。
為了避免這個問題,代碼修改如下:
for($i = 0; $i < 10; $i++) { $pid = pcntl_fork(); if($pid == -1) { echo "Could not fork!\n"; exit(1); } if(!$pid) { //child process workspace //TODO Api::refreshCache(); exit; //子進程邏輯執(zhí)行完后,馬上退出,以免往下走再fork子進程,不好控制 } }
只要在子進程邏輯執(zhí)行完后,加一個exit,一切都在撐握中了。這樣,只有一個父進程,父進程后續(xù)對子進程的管理也會清晰很多。
問題二:單例模式下DB連接被虐
/* * 前面或遠或近的地方,已經有一個$db = &MySQL::getInstance();了 */ for($i = 0; $i < 10; $i++) { $pid = pcntl_fork(); if($pid == -1) { echo "Could not fork!\n"; exit(1); } if(!$pid) { //child process workspace //TODO $db = &MySql::getInstance(); $sql = "XXX"; $result = $db->getAll($sql); exit; } }
這段代碼,十有八九都會報mysql has gone away.或者其它一些數(shù)據(jù)fetch方面的錯誤。究其原因,是因為各個子進程創(chuàng)建時,就已經繼承了父進程一份完全一樣的拷貝。對象可以拷貝,但是已創(chuàng)建的連接可不能拷貝成多個,由此產生的結果,就是各個進程都使用同一個mysql連接,各干各的事,最終產生莫名其妙的沖突。
解決辦法:
我們顯然不可能完全保證在fork進程之前,父進程不會創(chuàng)建mysql連接實例,因此,解決方案只能靠子進程本身了??梢韵胂螅覀冎恍枰谧舆M程中獲取的實例只與當前進程相關,這個問題就不存在了。解決辦法就是稍微改造一下mysql類實例化的靜態(tài)方式,與當前進程ID綁定。
public static function &getInstance() { static $instances = array(); $key = getmypid(); //獲取當前進程ID if(empty($instances[$key])) { //實例化mysql類動作 $classname = __CLASS__; $instances[$key] = new $classname(); } return $instances[$key]; }
總結:子進程創(chuàng)建時,拷貝了父進程當時擁有的所有資源,雖說后面對資源的修改互不影響,但DB連接卻還是同一個,造成運行混亂。
名稱欄目:PHPPCNTL多進程編程
文章起源:http://jinyejixie.com/article40/gdpcho.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供營銷型網站建設、域名注冊、網站導航、關鍵詞優(yōu)化、、自適應網站
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)