PHP開啟異步多線程執(zhí)行腳本

場景要求

客戶端調(diào)用服務(wù)器a.php接口,需要執(zhí)行一個長達(dá)5s-20s不等的耗資源操作,但是客戶端響應(yīng)請求時間為5秒(微信公眾賬號服務(wù)器請求響應(yīng)超時時間),5s以上無回復(fù)即斷開連接。

解決設(shè)想

客戶端調(diào)用a.php之后,a.php執(zhí)行異步多線程操作調(diào)用b.php,a.php調(diào)用成功后即刻反饋給客戶端回執(zhí),b.php自動執(zhí)行耗資源操作。

難點

PHP沒有真正實現(xiàn)多線程操作的方法。所以需要通過其它手段來進(jìn)行模擬多線程。

方案一

利用CURL非阻塞調(diào)用b.php,實現(xiàn)過程可以參考

http://blog.csdn.net/linvo/article/details/5956629

但是有一個問題,就是a.php會繼續(xù)等待b.php的響應(yīng)。

于是臨時想了一個解決方案:

在此處代碼中,將$curlopt_timeout改為1

/**  
     * 單個CURL調(diào)用超時限制   
     */    
    public $curlopt_timeout = 1;    
    private $param = array();  

但是這樣做就違背了curl本身的邏輯限制。

方案二

利用socket

在a.php中加入以下代碼

$fp = fsockopen("test.com", 80, $errno, $errstr, 30);  
if (!$fp){  
    echo 'error fsockopen';  
}  
else{  
    stream_set_blocking($fp,0);  
    $http = "GET /test/b.php HTTP/1.1\r\n";      
    $http .= "Host: test.com\r\n";      
    $http .= "Connection: Close\r\n\r\n";  
    fwrite($fp,$http);  
    fclose($fp);  
}  

即可實現(xiàn)a.php調(diào)用b.php無阻塞。

代碼中stream_set_blocking函數(shù)用來設(shè)定socket鏈接為無阻塞方式(默認(rèn)為阻塞)。

問題

在使用方案二以后,遇到了一個問題,即客戶端短時間內(nèi)多次調(diào)用a.php,出現(xiàn)部分請求 沒有執(zhí)行b.php 的情況。

解決方法:

在Nginx的nginx.conf文件中,查看worker_processes為1,判斷服務(wù)端響應(yīng)請求的線程啟動限制太大,得知服務(wù)器本身配置為雙核CPU,判斷2-4線程比較合適,于是修改worker_processes為4.問題得到解決!

報錯:stream_set_blocking() expects parameter 1 to be resource, null given
解決方法,修改php.ini函數(shù)設(shè)置,找到
disable_functions =
將proc_open和stream_socket_server兩個參數(shù)刪除
重啟php

完整代碼:

/**
     * @parem $url 網(wǎng)頁地址 http://www.test.com/test/test.php
     * @parem $port 網(wǎng)址端口 默認(rèn)80
     * @parem $t 腳本請求時間 默認(rèn)30s
     * @parem $method 請求方式 get/post
     * @parem $data ['test'=>'1']
     * */
    public function asyncPHP($url, $port = 80, $t = 30, $method = 'get', $data = null)
    {
        $info = parse_url($url);
        $fp   = fsockopen($info["host"], $port, $errno, $errstr, $t);
        //stream_set_blocking函數(shù)用來設(shè)定socket鏈接為無阻塞方式
        stream_set_blocking($fp, 0);
        // 判斷是否有數(shù)據(jù)
        if (isset($data) && !empty($data)) {
            $query = http_build_query($data); // 數(shù)組轉(zhuǎn)url 字符串形式
        } else {
            $query = null;
        }
        // 判斷 請求方式
        if ($method == 'post') {
            $head = "POST " . $info['path'] . " HTTP/1.0" . PHP_EOL;
        } else {
            $head = "GET " . $info['path'] . "?" . $query . " HTTP/1.0" . PHP_EOL;
        }
        $head .= "Host: " . $info['host'] . PHP_EOL; // 請求主機地址
        $head .= "Referer: " . $url . PHP_EOL;
        if (isset($data) && !empty($data) && ($method == 'post')) {
            $head .= "Content-type: application/x-www-form-urlencoded" . PHP_EOL;
            $head .= "Content-Length: " . strlen(trim($query)) . PHP_EOL;
            $head .= PHP_EOL;
            $head .= trim($query);
        } else {
            $head .= PHP_EOL;
        }
        fwrite($fp, $head);
        fclose($fp);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容