使用php curl 的并发能力可以做什么

在php中,没有多线程让编程变得简单。但在一些需要并发提升性能的场景下,显得有些无能为力,比如发起一些http请求。

但好在curl扩展可以让我们“并发”去请求网络资源。利用这个特点,我们能做很多有趣的事情。

最基础的,并发请求网络资源,提升处理速度。

并发访问代码

<?php
class ConcurrencyHTTP {
    private $_requests;
    private $_callbacks;
    private $_currentIndex = 0;
    public function get($url, $header = array(), $timeout = 30) {
    $this->_requests[$this->_currentIndex++] = array(
            "url"       => $url,
            "method"    => "GET",
            "timeout"   => $timeout,
            "header"    => $header
        );
        return $this;
    }

    public function post($url, $body, $header = array(), $timeout = 30)
    {
        $this->_requests[$this->_currentIndex++] = array(
            "url"       => $url,
            "method"    => "GET",
            "body"      => $body,
            "timeout"   => $timeout,
            "header"    => $header
        );
        return $this;
    }

    public function callback(callable $callback)
    {
        $currentIndex = $this->_currentIndex - 1;
        $this->_callbacks[$currentIndex] = $callback;
        return $this;
    }

    public function exec()
    {
        foreach ($this->_requests as $req) {
            $options = array(
                CURLOPT_HEADER          => $req["header"],
                CURLOPT_RETURNTRANSFER  => true,
                CURLOPT_TIMEOUT         => $req["timeout"],
                CURLOPT_URL             => $req["url"],
            );
            if ($req["method"] == "POST") {
                $options[CURLOPT_POST] = true;
                if (is_array($req["body"])) {
                    $options[CURLOPT_POSTFIELDS] = http_build_query($req['body']);
                } else {
                    $options[CURLOPT_POSTFIELDS] = $req['body'];
                }
            }
            $ch = curl_init();
            curl_setopt_array($ch, $options);
            $handles[] = $ch;
        }

        $mh = curl_multi_init();
        foreach ($handles as $ch) {
            curl_multi_add_handle($mh, $ch);
        }

        $running = null;
        $finished = 0;
        do {
            curl_multi_exec($mh, $running);
            curl_multi_select($mh);

            while ($info = curl_multi_info_read($mh)) {
                $ch = $info['handle'];
                if ($info['result'] != CURLM_OK) {
                    $code = $info['result'];
                    $data = curl_error($ch);
                } else {
                    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                    $data = curl_multi_getcontent($ch);
                }
                $index = array_search($ch, $handles, true);
                $this->_callbacks[$index]($data, $code);
                curl_multi_remove_handle($mh, $ch);
                curl_close($ch);
                $finished++;
            }
        } while ($running > 0);
        curl_multi_close($mh);
    }
}

调用很简单,直接链式调用get和callback即可。get用于组装请求数据,callback用户设置数据到来时的回调函数。

$concurrency = new ConcurrencyHTTP();
$concurrency->get("http://baidu.com")
->callback(function($content, $code) {
echo $content;
echo $code;
})
->get("http://imhuchao.com")
->callback(function($content, $code) {
echo $content;
echo $code;
})
->exec();

在某些情况下,如果同一个服务我们有多个节点,我们可能需要取回响应速度比较快的节点。

获取最快的节点

上面的代码稍微改改就能实现,我们改动exec方法,增加一个fastestOne参数。当有数据返回时立即结束。改动结果如下:

public function exec($fastestOne = false)
    {
        foreach ($this->_requests as $req) {
            $options = array(
                CURLOPT_HEADER          => $req["header"],
                CURLOPT_RETURNTRANSFER  => true,
                CURLOPT_TIMEOUT         => $req["timeout"],
                CURLOPT_URL             => $req["url"],
            );
            if ($req["method"] == "POST") {
                $options[CURLOPT_POST] = true;
                if (is_array($req["body"])) {
                    $options[CURLOPT_POSTFIELDS] = http_build_query($req['body']);
                } else {
                    $options[CURLOPT_POSTFIELDS] = $req['body'];
                }
            }
            $ch = curl_init();
            curl_setopt_array($ch, $options);
            $handles[] = $ch;
        }

        $mh = curl_multi_init();
        foreach ($handles as $ch) {
            curl_multi_add_handle($mh, $ch);
        }

        $running = null;
        $finished = 0;
        do {
            curl_multi_exec($mh, $running);
            curl_multi_select($mh);

            while ($info = curl_multi_info_read($mh)) {
                $ch = $info['handle'];
                if ($info['result'] != CURLM_OK) {
                    $httpCode = $info['result'];
                    $httpBody = curl_error($ch);
                } else {
                    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                    $httpBody = curl_multi_getcontent($ch);
                }
                $index = array_search($ch, $handles, true);
                $this->_callbacks[$index]($httpBody, $httpCode);
                curl_multi_remove_handle($mh, $ch);
                curl_close($ch);
                $finished++;
            }
            // 当有返回结果时,break跳出循环,不再等待其他结果
            if ($fastestOne && $finished > 0) {
                break;
            }
            
        } while ($running > 0);
        curl_multi_close($mh);
    }

 

你可能还喜欢下面这些文章

Shell中的条件判断语句if的用法

shell中的if语法是最让我头疼的语法之一,它的判断就向使用USB插头一样——拿起来插入不行,翻转再插入还不行,再翻转插入行了!为了搞清楚这部分语言,我收集了一些文章关于if条件判断的用法,希望对你也有些帮助。一、基本语法if [ command ]; then 符合该条件执行的语句fiif [ command ];then 符合该条件执行的语句elif [ command ];then 符合该条件执行的语句else 符合该条件执行的语句fi语法说明bash shell会按顺序执行if语句,如果command执行后且它的返回状态是0,则会执行符合该条件执行的语

c语言的位操作

一、基本位操作|或&与~取反^异或<<左移>>右移二、位操作的常见用法1.获取某位的值#define BitGet(Number,pos) ((Number)|= 1<<(pos)) //把某位置1#define BitGet(Number,pos) ((Number) &= ~(1<<(pos)) //把某位置0#define BitGet(Number,pos) ((Number) >> (pos)&1)) //用宏得到某数的某位#define BitGet(Number,pos) ((Number) ^=

基于信息熵原理分词的php实现

基于信息熵原理分词这个概念很早了,用php实现了个,一气呵成,代码自然是,反正我也没有二次检查,呵呵。不过耗费内存是真的,真的很消耗内存!写这个的好处就是我明白了很多东西…代码如下<?php/** * 基于信息熵的无词典分词*/class partword{        /**     * 词语最大长度    */    public $maxwordlen = 5;    /**     * 需要进行分词的文字    */    public $text;    /**     * 字符串长度    */    private $len;    /**     * 切分的单个文字

一个将网页里面的(图片,链接地址)相对路径转化为绝对路径的php实现方法

抓取网页的时候有时候会需要下载里面的图片或者其他附件,但有的网页里面用的是相对路径,这时候就要转化为绝对路径。 /*** url补全,相对url转化为绝对url* 作用是补全url*/function url2abs($srcurl,$baseurl){  $srcinfo = parse_url($srcurl);   //print_r($srcinfo);   if(isset($srcinfo[‘scheme’])) {      return $srcurl;    }  $baseinfo = parse_url($baseurl);    $url = $baseinfo[‘sc

openssl生成rsa公钥私钥

输入opensslj你如openssl交互界面OpenSSL>生成rsa私钥OpenSSL> genrsa -out private_key 1024Generating RSA private key, 1024 bit long modulus………………….++++++…………++++++e is 65537 (0x10001)生成公钥OpenSSL> rsa -in private_key -pubout -out public_keywriting RSA key

赞赏

微信赞赏支付宝赞赏

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注