开发中可能遇到不需要通知用户的操作,比如记录一些访问信息


有些操作会比较耗时,而这些时间用户是不需要承担的,第一个想到的肯定是多线程

而使用php的兄弟们就比较苦逼了,这玩意是不支持多线程的


虽然有第三方库可以安装,但是非常费劲,经过多番尝试,找到了如下折中方案


//以这个方法为例
public function timeOut($msg){
    sleep(100);
    dump('我是个耗时操作' . $msg);
}

public function index(){
   timeOut("666");
}


接下来开始改造

将耗时方法改造为接口,使用fsockopen()调用,这里php会开启新线程调用

我们只调用不处理返回结果即可,也能实现类似多线程的效果


工具类如下


/**
 * php多线程接口调用
  *
 * @param $url   接口地址
 * @param $method   调用方式
 * @param array $params 参数
 * @return string
 */
function sendHttpRequest($url, $method, $params = array()){


    //处理url
    $urlInfo = parse_url($url);
    if (isset($urlInfo['scheme']) && strcasecmp($urlInfo['scheme'], 'https') === 0) {
        //注意,如果为ssl需要开启PHP的ssl支持
        $prefix = 'ssl://';
        $port = 443;
    }else{
        $prefix = 'tcp://';
        $port = empty($urlInfo['port']) ? 80 : $urlInfo['port'];
    }
    $host = $urlInfo['host'];
    $path = $urlInfo['path'];

    
    //处理参数
    $contentType = '';
    $contentLength = '';
    $requestBody = '';
    if($method === 'GET') {
        $path = $path . '?' . http_build_query($params);
    }else{
        $requestBody = http_build_query($params);
        $contentType = "Content-Type: application/x-www-form-urlencoded\r\n";
        $contentLength = "Content-Length: " . strlen($requestBody) . "\r\n";
    }


    //尝试建立连接
    $errno = 0;
    $errstr = '';
    $fp = fsockopen($prefix . $host, $port, $errno, $errstr,  30);

    //建立失败
    if (!$fp) {
        return '';
    }
    if ($errno || !$fp) {
        return '';
    }

    
    //拼接请求
    $out = "$method $path HTTP/1.1\r\n";
    $out .= "Host: $host\r\n";
    $out .= $contentType;
    $out .= $contentLength;
    $out .= "Connection: Close\r\n\r\n";
    $out .= $requestBody;

    
    //调用接口,不处理返回结果
    fputs($fp, $out);
    usleep(20000);
    fclose($fp);
}



接口改造,其实就是加两行代码,让断开连接继续执行

还需要获取参数


public function timeOut(){
    set_time_limit(0);
    ignore_user_abort(true);//设置与客户机断开是否会终止执行
    
    $msg = I('msg');
    sleep(100);
    dump('我是个耗时操作');
}



调用方式

public function index(){
    $param = array(
    'msg' => '666'
    );
    
    //url需要完整
   $this->sendHttpRequest("http://127.0.0.1:8080/Home/Index/timeOut", "POST", $param);
}


如果是使用的nginx服务器,最好调整一下超时时间

php.ini和php-fpm.conf都需要调整

个人网站运营不易ヾ(◍°∇°◍)ノ゙如果有帮到你赞助一下吧

Kevin博客
  • 最新评论
  • 总共0条评论