前邊文章說過:web-server會建立一個線程(進程)來處理收到的php請求。(使用線程還是進程的區別見博文:http://blog.csdn.net/NRC_DouNingBo/archive/2011/06/29/6575807.aspx)。那這個請求怎樣才算處理完畢呢?怎樣才能讓web-server回收這個線程呢??
user進行一次web請求,其是要請求資料的。所以:一些一個php指令碼最後肯定是需要echo一些資料來返回給請求它的user的(這裡的user指的是瀏覽器)。網上也有很多文章在討論說:echo速度慢,其實這是沒有正明白:怎樣才算一個php請求的完整過程的緣故。
比如我寫如下php指令碼:
<?php<br />$var['key'] = "temp";<br />echo json_encode($var);<br />?>
原本我認為:當執行完第二句echo之後這個請求就算執行完了,然後就該web-server回收這個線程了。問題是:這個時候真的執行完了嗎?沒有!
①對於echo,var_dump()等而言:其實要把資料返回給user(瀏覽器)的。echo的執行過程為:其會把資料發送給user,user收到資料並反饋回來告知:我已經收到了。echo函數收到這個成功訊號之後:其才會認為:自己使命結束了,這個函數才算執行完畢。
因為有上述這麼個過程,會導致大量問題,比如:如果user的網路不好,那這個等待發送成功訊號的過程會很慢,嚴重影響這個php指令碼的執行速度,爭議延長其執行時間,同時導致這個請求的執行線程一直無法回收。 那拿到具體項目上來說:幾百萬個請求同時請求一個相同的伺服器,由於每個的執行時間都過程,這導致大量處理線程無法及時回收,導致伺服器端積攢了大量線程。這回嚴重影響伺服器的響應!!
那怎樣解決這些問題呢?要解決這個問題就要從產生這個問題的根源上著手。根源就在於如上所說的:echo本身執行較慢以及php處理線程未釋放。
①為了處理echo較慢的問題,我們可以開啟php的輸出緩衝。亦即:每次echo返回給使用者的資料我們直接讓php將之存入php輸出緩衝中並給出成功應答,這時echo函數會認為其已經達到user端並成功了,從而執行完畢。
用這種辦法解決了echo處理慢的問題;但是echo執行完後php處理線程並未釋放,為什麼呢?因為此時php的輸出緩衝中還有剛剛存入的資料沒有發送出去,此時php線程當然不能釋放。所以他還得等自己輸出緩衝中的資料都發送出去了才能釋放線程。從這一點上來說:使用之中方法後:線程存在的時間根本就沒有減少,只是把原本echo消耗的時間轉義到了輸出緩衝上而已。 同時php緩衝有大小限制,若echo的資料比這個限制要大,則根本無法存到輸出緩衝中。
②最終極的解決辦法是:我們開啟apache的輸出緩衝。這樣執行echo時:直接把資料發送到apache的輸出緩衝中並返回成功訊號。echo函數收到訊號就認為是成功執行了所以就執行完畢。此時php線程發現自己:整個指令碼都執行完畢了,也沒有輸出緩衝要去發送,自己的所有工作都做完了,於是乎就釋放自己本身了。
用這種辦法:會真正減少一個php處理進程的執行時間,讓這個線程儘快釋放,從而減少伺服器上的線程數量堆積!! 其本質是:把處理時間由php轉給了apache! 但是這樣好處是顯而易見的:無論是apache還是php線程去處理這個,都是要消耗同樣的時間等資源。但是用php還要額外多了線程消耗。開啟了apache輸出緩衝後:就大大減少了伺服器上的線程數量堆積!!
其實這種辦法並沒有讓使用者更快的受到資料,亦即:對使用者本身而言沒有任何最佳化;但是對伺服器卻是很大的最佳化,因其加快了每個請求的處理速度,避免了線程堆積導致的問題!!!