客戶端呼叫a.php之後,a.php執行非同步多執行緒操作呼叫b.php,a.php呼叫成功後即刻反饋給客戶端回執,b.php自動執行耗資源操作。
php沒有真正實現多執行緒操作的方法。所以需要通過其它手段來進行模擬多執行緒。
利用curl非阻塞呼叫b.php,實現過程可以參考
但是有乙個問題,就是a.php會繼續等待b.php的響應。
於是臨時想了乙個解決方案:
在此處**中,將$curlopt_timeout改為1
[php]view plain
copy
/**
* 單個curl呼叫超時限制
*/
public $curlopt_timeout = 1;
private $param = array();
但是這樣做就違背了curl本身的邏輯限制。
利用socket
在a.php中加入以下**
[php]view plain
copy
$fp = fsockopen("test.com", 80, $errno, $errstr, 30);
if (!$fp)
else
即可實現a.php呼叫b.php無阻塞。
**中stream_set_blocking函式用來設定socket鏈結為無阻塞方式(預設為阻塞)。
在使用方案二以後,遇到了乙個問題,即客戶端短時間內多次呼叫a.php,出現部分請求 沒有執行b.php 的情況。
解決方法:
在nginx的nginx.conf檔案中,檢視worker_processes為1,判斷服務端響應請求的執行緒啟動限制太大,得知伺服器本身配置為雙核cpu,判斷2-4執行緒比較合適,於是修改worker_processes為4.問題得到解決!
某些操作,如使用者註冊後郵件傳送,記錄日誌等一些耗時操作可以轉化為非同步操作!當php執行在fastcgi模式是提供了fastcgi_finish_request()函式,看下面例子:
<?php
echo '輸出給客戶端的內容';
fastcgi_finish_request();
sleep(3);
echo '放心吧,這裡的內容並不會輸出';
file_put_contents('log.txt','這是客戶端響應結束後,伺服器段指令碼繼續執行後生成');
執行了次指令碼,你會發現客戶端輸出上面一句話,fastcgi_finish_request()下面的內容並沒有輸出,但是卻生成了檔案,如此說明了呼叫了fastcgi_finish_request後,客戶端響應就已經結束,但與此同時服務端指令碼卻繼續執行。這在一定程度上提高了響應速度,當然更科學的做法是:使用fastcgi_finish_request()函式整合佇列訊息,可以把訊息非同步發 送到佇列。
fastcgi_finish_reques()函式的缺點:
1.php fastcgi 程序數有限,正在處理非同步操作的php-cgi程序,無法處理新請求;
2.如果併發訪問量較大,php-cgi程序數用滿,新訪問請求,將沒有php-cgi去處理。nginx伺服器會出現: 502 bad gateway。
*******************************
瀏覽器和伺服器之間是通過 http 協議進行連線通訊的。這是一種基於請求和響應模型的協議。瀏覽器通過 url 向伺服器發起請求,web 伺服器接收到請求,執行一段程式,然後做出響應,傳送相應的html**給客戶端。
這就有了乙個問題,web 伺服器執行一段程式,可能幾毫秒就完成,也可能幾分鐘都完不成。如果程式執行緩慢,使用者可能沒有耐心等下去,就關閉瀏覽器了。
而有的時候,我們更本不關心這些耗時的指令碼的返回結果,但卻還要等他執行完返回,才能繼續下一步。
那麼有沒有什麼辦法,只是簡單的觸發呼叫這些耗時的指令碼然後就繼續下一步,讓這些耗時的指令碼在服務端慢慢執行?
經過試驗,總結出來幾種方法,和大家share:
1. 最簡單的辦法,就是在返回給客戶端的html**中,嵌入ajax呼叫,或者,嵌入乙個img標籤,src指向要執行的耗時指令碼。
這種方法最簡單,也最快。伺服器端不用做任何的呼叫。
但是缺點是,一般來說ajax都應該在onload以後觸發,也就是說,使用者點開頁面後,就關閉,那就不會觸發我們的後台指令碼了。
而使用img標籤的話,這種方式不能稱為嚴格意義上的非同步執行。使用者瀏覽器會長時間等待php指令碼的執行完成,也就是使用者瀏覽器的狀態列一直顯示還在load。
當然,還可以使用其他的類似原理的方法,比如script標籤等等。
2. popen()
resource popen ( string command, string mode );
//開啟乙個指向程序的管道,該程序由派生給定的 command 命令執行而產生。開啟乙個指向程序的管道,該程序由派生給定的 command 命令執行而產生。
所以可以通過呼叫它,但忽略它的輸出。
pclose(popen("/home/xinchen/backend.php &", 'r'));
這個方法避免了第乙個方法的缺點,並且也很快。但是問題是,這種方法不能通過http協議請求另外的乙個webservice,只能執行本地的指令碼檔案。並且只能單向開啟,無法穿大量引數給被呼叫指令碼。
並且如果,訪問量很高的時候,會產生大量的程序。如果使用到了外部資源,還要自己考慮競爭。
3. 使用curl
這個方法,設定curopt_timeout為1(最小為1,鬱悶)。也就是說,客戶端至少必須等待1秒鐘。
$ch = curl_init();
$curl_opt = array(curlopt_url, '',
curlopt_returntransfer, 1,
curlopt_timeout, 1,);
curl_setopt_array($ch, $curl_opt);
curl_exec($ch);
curl_close($ch);
4. 使用fsockopen
這個方法應該是最完美的,但是缺點是,你需要自己拼出http的header部分。
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) else */
fclose($fp);
}所以,總體來看,最好用,最簡單的還是第一種方法。
最完美的應該是最後一種,但是比較複雜
如果有更好的辦法,歡迎交流。
php 非同步執行
header host url array host r n http 1.1 host域不能省略 header connection close r n r n header connection close r n r n if empty post data out connection cl...
php非同步處理
namespace index controller usecore controller class test extends controller public function test12 php非同步請求 param host string 主機位址 param path string 路...
php學習筆記 popen 非同步呼叫
寫了一年的php後台,第一次在實踐中需要用到非同步程式設計。通過一晚上的搜尋,找到了乙個有效的非同步程式設計方法,即popen 該函式會建立乙個管道,所以不會對php造成阻塞。但非同步是有條件的,需要在command後面加上 表示後台執行,另外如果使用fread來讀取管道資料,將會造成程序阻塞。用法...