PHP 提前輸出響應後台繼續執行

2021-08-02 22:03:42 字數 3921 閱讀 8752

瀏覽器和伺服器之間是通過http進行通訊的,瀏覽器傳送請求給伺服器,伺服器處理完請求後,傳送響應結果給瀏覽器,瀏覽器展示給使用者。如果伺服器處理請求時間比較長,那麼瀏覽器就需要等待伺服器的處理結果。

但是,有時候,瀏覽器不需要等待伺服器的處理結果,只要傳送的請求已經被伺服器接收到。所以,這種情況下,瀏覽器希望伺服器接收到請求立即返回乙個響應,比如字串'success'。這樣瀏覽器可以繼續執行後續**。

在php中,很容易做到。如果伺服器使用的是nginx+fpm,可以使用下面的**:

echo

'success';

fastcgi_finish_request();

// 執行耗時**.....

如果伺服器使用的是apache,可以使用下面的**:

ob_end_flush();

ob_start();

echo 'success';

header("content-type: text/html;charset=utf-8");

header("connection: close");

header('content-length: '. ob_get_length());

ob_flush();

flush();

// 執行耗時**.....

乙個靜態頁面:index.html,**如下:

測試php提前輸出響應title>

head>

script>

function

getcurtime(d)

function

getother(url)

});}console.log(getcurtime(new

date()));

$.ajax(

});script>

body>

html>

瀏覽器首先通過ajax請求a.php,該php檔案執行是比較耗時的,要等到a.php的響應後繼續請求b.php檔案。如果a.php不提前輸出響應,ajax必須等待響應後才能去請求b.php。

上面**,會在每次請求傳送開始和返回時列印出時間。

兩個php檔案:1.php 、 2.php

a.php檔案內容:

<?php 

echo

'success';

sleep(5);

?>

上面**使用sleep函式模擬耗時任務,耗時5秒。

b.php檔案內容:

<?php 

echo

'this is b.php';

?>

瀏覽器執行index.html,檢視console日誌如下:

console日誌

發現第二次請求時間比第一次請求時間遲5秒,正好是a.php檔案的執行時間,說明瀏覽器需要等待a.php檔案執行完才能去請求b.php檔案。

下面修改a.php檔案內容,提前輸出響應,**如下:

<?php 

if(!function_exists('fastcgi_finish_request'))

echo

'success';

if(!function_exists('fastcgi_finish_request')) else

sleep(5);

?>

瀏覽器執行index.html,檢視console日誌如下:

console日誌

兩次請求的時間都一樣,表示a.php已經提前輸出響應了。

開發web應用程式不可避免的要用到session,修改一下a.php檔案內容如下:

<?php 

session_start();

$_session['uname'] = 'jianshu';

if(!function

_exists('fastcgi_finish_request'))

echo 'success';

if(!function

_exists('fastcgi_finish_request')) else

sleep(5);

?>

修改b.php檔案內容如下:

<?php 

session_start();

echo $_session['uname'];

echo

'this is b.php';

?>

瀏覽器執行index.html,檢視console日誌如下:

console日誌

發現第一次和第二次請求時間一樣,說明第一次請求已經提前輸出響應了,但是第二次請求的響應時間卻比請求傳送時間遲5秒。第二次請求的是b.php檔案,b.php檔案內容只有幾行**,為什麼會執行5秒才返回。

原因是,session是有鎖的。為防止併發的寫session資料,php自帶的的檔案儲存session資料是加了乙個互斥鎖。程式執行session_start(),此時當前程式就開始持有鎖。程式結束,此時程式自動釋放session的鎖。

瀏覽器第一次請求a.php檔案,對session檔案進行加鎖,雖然提前輸出響應,但程式還在執行,session檔案的鎖還未釋放。所以,第二次請求b.php檔案時,由於b.php檔案的開始就要開啟session檔案,但session檔案的鎖還未釋放,需要等待a.php執行完,也即要等待5秒。

一般session檔案跟session_id有關,每個session_id會建立乙個session檔案,下面可以看到兩次請求帶過去的session_id是一樣的。

a.php檔案請求sessid

b.php檔案請求sessid

如何解決session檔案加鎖的問題,可以使用session_write_close函式,該函式的作用就是資料寫入session檔案並結束會話。

修改a.php檔案,在使用session**後面加上session_write_close函式。

<?php 

session_start();

$_session['uname'] = 'jianshu';

session_write_close();

............

瀏覽器執行index.html,檢視console日誌如下:

console日誌

發現沒有等待存在了。實際開發中,使用完session,可以加上session_write_close()函式,減少伺服器開銷。

php 後台執行,PHP開啟守護程序後台執行

只能在linux環境執行有時候難免要用到php守護程序,需要在cli模式下保持執行,直接一段 即可,linux php守護程序 啟動 停止 重啟 查詢狀態 class servicedeamon else else if pid 0 else else else else else echo pro...

Linux後台執行python程式,輸出日誌

實際開發時,會常常有需要執行很長時間的python程式,這時最佳策略就是將它放在linux伺服器後台執行,並且及時更新訊息。1 基礎命令 nohup python u py log 2 1 2 其他 只記錄錯誤資訊 nohup python u py dev null 2 error.log 2 1...

Linux將程式放在後台執行,關閉終端繼續執行

最近使用shell指令碼的形式執行任務,結果發現執行之後就一直在程式介面,ctrl c退出後程式終止,關閉終端後程式也退出,需要將程式交給linux去管理和執行,查詢了下資料 使用 nohup命令,具體如下 後台執行build.sh指令碼 nohup build.sh run build.sh的列印...