您好,登錄后才能下訂單哦!
PHP中如何實(shí)現(xiàn)異步非阻塞,很多新手對此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
在PHP5.3.3版本之后,不管是Nginx還是Apache服務(wù)器,只要運(yùn)行在FastCGI模式下,均可使用該方法,官方解釋的作用是沖刷(flush)所有響應(yīng)的數(shù)據(jù)給客戶端。
boolean fastcgi_finish_request ( void )
此函數(shù)沖刷(flush)所有響應(yīng)的數(shù)據(jù)給客戶端并結(jié)束請求。 這使得客戶端結(jié)束連接后,需要大量時(shí)間運(yùn)行的任務(wù)能夠繼續(xù)運(yùn)行。
用法:可以在讀寫大文件、循環(huán)更新數(shù)據(jù)庫等不影響結(jié)果的操作之前,執(zhí)行該函數(shù),把結(jié)果返回給客戶端,php會(huì)繼續(xù)執(zhí)行下面的邏輯而不影響客戶端的響應(yīng)時(shí)間。
fsockopen()方法可以打開一個(gè)網(wǎng)絡(luò)連接或Unxi套接字連接,stream_set_blocking()方法可以為資源流設(shè)置非阻塞或者阻塞模式,
使用fsockopen()打開一個(gè)網(wǎng)絡(luò)連接或者一個(gè)Unix套接字連接,再用stream_set_blocking()設(shè)置資源成非阻塞模式請求,則該資源請求會(huì)是非阻塞的:
bool stream_set_blocking ( resource $stream , int $mode )
注:$mode=0則是非阻塞的,1則是阻塞的模式。
用法:
<?php $fp = fsockopen('www.oschina.net', 80, $errno, $errstr, 30); if( !$fp ) { die('error fsockopen'); } // 轉(zhuǎn)換到非阻塞模式 stream_set_blocking($fp, 0); $http = "GET /Save.php / HTTP/1.1\r\n"; $http .= "Host: www.oschina.net\r\n"; $http .= "Connection: Close\r\n\r\n"; fwrite($fp, $http); while (!feof($fp)) { echo fgets($fp, 128); } fclose($fp);
cURL除了我們通常使用的curl_init來初始化和發(fā)送post和get請求之外,還可以使用curl_multi_init()方法來實(shí)現(xiàn)異步請求,其原理是使用系統(tǒng)的select這個(gè)多路I/O復(fù)用機(jī)制來異步發(fā)送請求。
通常的用法:
<?php // 創(chuàng)建一對CURL資源 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "www.oschina.net"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); $output = curl_exec($ch); echo $output;
異步用法:
<?php $time = time(); // 創(chuàng)建一對CURL資源 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "www.oschina.net"); curl_setopt($ch, CURLOPT_HEADER, TRUE); // 增加2個(gè)句柄 $mh = curl_multi_init(); curl_multi_add_handle($mh, $ch); // 執(zhí)行批處理句柄 $running= null; do { usleep(10000); // 延遲10000微秒 curl_multi_exec($mh, $running); } while ( $running>0 ); // 關(guān)閉全部句柄 curl_multi_remove_handle($mh, $ch); curl_multi_close($mh); echo "\n total time: ".(time()-$time)."\r";
4、使用Gearman/Swoole等PHP異步擴(kuò)展或框架
5、使用緩存和隊(duì)列
通常復(fù)雜的處理邏輯,我們可以將參數(shù)推入隊(duì)列,如redis或kafka的隊(duì)列服務(wù),開啟一個(gè)消費(fèi)進(jìn)程去處理隊(duì)列事務(wù)。
如redis服務(wù)的list結(jié)構(gòu),在之前篇章有過說明。
6、使用pcntl_fork()
在PHP4.1.0版本之后都支持了該函數(shù),使用前需要安裝支持pcntl擴(kuò)展并添加支持。
官方文檔:在當(dāng)前進(jìn)程當(dāng)前位置產(chǎn)生分支(子進(jìn)程),這個(gè)子進(jìn)程僅PID(進(jìn)程號(hào)) 和PPID(父進(jìn)程號(hào))與其父進(jìn)程不同
說明:int pcntl_fork ( void )
成功時(shí),在父進(jìn)程執(zhí)行線程內(nèi)返回產(chǎn)生的子進(jìn)程的PID,在子進(jìn)程執(zhí)行線程內(nèi)返回0;
失敗時(shí),在父進(jìn)程上下文返回-1,不會(huì)創(chuàng)建子進(jìn)程,并且會(huì)引發(fā)一個(gè)PHP錯(cuò)誤。
用法:
<?php $pid = pcntl_fork(); // 父進(jìn)程和子進(jìn)程都會(huì)執(zhí)行下面代碼 if( $pid== -1 ) { // 錯(cuò)誤處理: 創(chuàng)建子進(jìn)程失敗時(shí)返回-1 die('could not fork'); } elseif ( $pid ) { //父進(jìn)程會(huì)得到子進(jìn)程號(hào),所以這里是父進(jìn)程執(zhí)行的邏輯 pcntl_wait($status); // 等待子進(jìn)程中斷,防止子進(jìn)程成為僵尸進(jìn)程 echo '父進(jìn)程:'.$status; } else { // 子進(jìn)程得到的$pid為0, 所以這里是子進(jìn)程執(zhí)行的邏輯 echo '子進(jìn)程'; } exit();
并發(fā)IO問題一直是服務(wù)器端編程中的技術(shù)難題,從最早的同步阻塞直接Fork進(jìn)程,到Worker進(jìn)程池/線程池,到現(xiàn)在的異步IO、協(xié)程。阻塞和非阻塞關(guān)注的是程序在等待調(diào)用結(jié)果(消息,返回值)時(shí)的狀態(tài)?,F(xiàn)在網(wǎng)絡(luò)的日益發(fā)展,對響應(yīng)時(shí)間和處理并發(fā)的要求越來越高,所以異步非阻塞的需求也越來越多,優(yōu)點(diǎn)也顯而易見:
1、非阻塞調(diào)用指在不能立刻得到結(jié)果之前,該調(diào)用不會(huì)阻塞當(dāng)前線程,能及時(shí)返回響應(yīng),減少響應(yīng)時(shí)間;
2、高并發(fā),同步阻塞IO模型的并發(fā)能力依賴于進(jìn)程/線程數(shù)量,響應(yīng)時(shí)間的下降可以帶來更多的并發(fā)能力。
當(dāng)然,異步非阻塞又存在缺點(diǎn):
1、啟動(dòng)大量進(jìn)程會(huì)帶來額外的進(jìn)程調(diào)度消耗。非阻塞模式下,如果大量線程已經(jīng)返回響應(yīng)而仍然在執(zhí)行計(jì)算操作,會(huì)使CPU利用率不可控的增高;
2、這種模型嚴(yán)重依賴進(jìn)程的數(shù)量解決并發(fā)問題,一個(gè)客戶端連接就需要占用一個(gè)進(jìn)程,工作進(jìn)程的數(shù)量有多少,并發(fā)處理能力就有多少。操作系統(tǒng)可以創(chuàng)建的進(jìn)程數(shù)量是有限的;
3、過多的異步和多線程模型會(huì)造成編碼困難或線程混亂,如出現(xiàn)大量僵尸進(jìn)程等。
1、一般情況下,我們不贊成用異步回調(diào)的方式去做功能開發(fā),傳統(tǒng)的PHP同步方式實(shí)現(xiàn)功能和邏輯是最簡單的,也是最佳的方案。像node.js這樣到處callback,只是犧牲可維護(hù)性和開發(fā)效率;
2、有些時(shí)候很適合用異步,比如FTP、聊天服務(wù)器,smtp,代理服務(wù)器等等此類以通信和讀寫磁盤為主,功能和業(yè)務(wù)邏輯其次的服務(wù)器程序;
3、異步非阻塞和多線程模型推薦:
(1)swoole框架:fpm里,通過swoole_client把url發(fā)送到swoole的server,swoole_server天然支持并行請求,把匯總的結(jié)果返回到fpm;
這也是當(dāng)下PHP最火的異步多線程框架,可以了解一下韓天峰的文章:http://rango.swoole.com/
(2)recoil框架:https://github.com/recoilphp/recoil
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。