本篇文章給大家帶來的內容是關於php中fastcgi_finish_request的介紹及其實現非阻塞的代碼,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所協助。
前言
在實際項目中經常會有這樣的需求,對於前端發過來的請求,需要在後端進行長時間的處理,但為了讓使用者有更好的體驗,為了讓PHP在後端處理長時間任務時不阻塞,快速響應頁面請求,因此在這裡對fastcgi_finish_request的應用進行總結歸納。當然php實現非阻塞的方式有很多種,比如非同步指令碼、swoole,但個人認為fastcgi_finish_request最為簡單方便。
基本應用
fastcgi_finish_request介紹
(PHP 5 >= 5.3.3, PHP 7)
fastcgi_finish_request — 沖刷(flush)所有響應的資料給用戶端
boolean fastcgi_finish_request ( void )
此函數沖刷(flush)所有響應的資料給用戶端並結束請求。 這使得用戶端結束串連後,需要大量時間啟動並執行任務能夠繼續運行。
傳回值
成功時返回 TRUE, 或者在失敗時返回 FALSE
注意問題
PHP 與 Web 服務器使用了PHP-FPM(FastCGI進程管理器),那通過fastcgi_finish_request() 函數能馬上結束會話,而 PHP 線程可以繼續在後台運行。也就是說只針對php-fpm的進程管理方式才能使用該函數
只要代碼運行到這個位置,就已經斷開請求返回參數給用戶端了。接下來的代碼都和用戶端沒有關係了。也就是說對於輸出在頁面的內容必須放在fastcgi_finish_request函數之前
fastcgi_finish_request()結束用戶端串連之後,已耗用時間依然會受max_execution_time逾時時間的影響,也就是說如果預計到代碼在後端執行時間比較久,還是要設定set_time_limit(0)
在高並發下執行時間過久也會導致fastcgi進程不夠用,不能及時釋放,就會爆502錯誤了。
應用
echo "program start...";file_put_contents('/tmp/garylog.log','start-time:'.date('Y-m-d H:i:s')."\n", FILE_APPEND);fastcgi_finish_request();sleep(1);// set_time_limit(0);// sleep(150);$num = 25;$num += 1;sleep(5);echo 'debug...';file_put_contents('/tmp/garylog.log', 'start-proceed:'.$num.',時間'.date('Y-m-d H:i:s')."\n", FILE_APPEND);sleep(10);file_put_contents('/tmp/garylog.log', 'end-time:'.date('Y-m-d H:i:s')."\n", FILE_APPEND);
運行測試
相容非php-fpm
從代碼的可移植性講的話, 可以在代碼中附上如下代碼:
if (!function_exists("fastcgi_finish_request")) { function fastcgi_finish_request() { } }
不會造成代碼部署在非fpm環境下造成問題.
保證進程單一運行
對於上面說到的問題:在高並發下執行時間過久也會導致fastcgi進程不夠用,不能及時釋放。同時我們的需求僅僅是為了起到觸發的作用,並不需要每次運行,那麼可以考慮使用下面的方法,避免重複佔用進程。
$processId = realpath(__FILE__) . '-' . get_class($this);$filename = md5($processId);$file = '/tmp/'.$filename;if(!file_exists($filename)){ file_put_contents($file, getmypid());}else{ return true; }## do somthing 需要長時間處理的代碼//處理完成後刪除進程id記錄檔案unlink($file);