基于curl的并行请求,实现php中的伪多线程

<?php

/**
 * 基于 curl_multi 的并行处理
 *
 * 使用示例
 * Helper_Multicurl::add_curl('url1', Helper_Multicurl::mk_curl('get', $url1));
 * Helper_Multicurl::add_curl('url2', Helper_Multicurl::mk_curl('get', $url2));
 * $ret = Helper_Multicurl::multi_exec();
 *
 * @author  肖武 <tsxw24@gmail.com>
 * @version 2012-9-14 15:06 #multicurl.php
 */
class Helper_Multicurl {
    static private $mh     = null;
    static private $arr_ch = array();//curl句柄列表

    /**
     * 创建curl会话,返回curl句柄
     *
     * @param string $type   请求方式,取值:get,post
     * @param string $url    url地址,可包含问号
     * @param array  $data   key-value对,post或get的参数
     * @param array  $ex_arg 扩展参数,常用参数如下:
     * array(
     *  CURLOPT_COOKIE     => string 设定HTTP请求中"Cookie: "部分的内容。多个cookie用分号分隔,分号后带一个空格(例如, "fruit=apple; colour=red")。
     *  CURLOPT_REFERER    => string 请求头中"Referer: "的内容
     *  CURLOPT_USERAGENT  => string "User-Agent: "头的字符串。如:“Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)”
     *  CURLOPT_HTTPHEADER => array  header头列表,如:array('host:http://abc.com','Content-type: text/plain')
     *  CURLOPT_TIMEOUT    => int    超时时间,秒
     * )
     *
     * @return resource
     */
    static public function mk_curl($type, $url, array $data=array(), array $ex_arg=array()) {
        //初始化curl会话
        $ch = curl_init();

        //curl参数
        $option = array(
            CURLOPT_RETURNTRANSFER => 1,//返回请求结果
        );

        //get 参数处理(url处理)
        if ($type=='get' && $data) {
            $url .= (strpos($url, '?') ? '&' : '?').http_build_query($data);
        }
        $option[CURLOPT_URL] = $url;

        //post 参数处理
        if ($type=='post' && $data) {
            $option[CURLOPT_POSTFIELDS] = $data;
        }

        //其它参数合并
        $option += $ex_arg;

        //批量设置会话参数
        curl_setopt_array($ch, $option);

        return $ch;
    }

    /**
     * 初始化批量curl会话
     */
    static private function _multi_init() {
        if (is_null(self::$mh)) {
            self::$mh = curl_multi_init();
        }
    }

    /**
     *  清理数据,恢复初始状态
     */
    static private function _clear() {
        self::$mh     = null;
        self::$arr_ch = array();
    }

    /**
     * 添加curl句柄到批量处理中
     *
     * @param string   $k  用于区分不同请求的key,最终的返回结果会和key对应。若有重复后面的覆盖前面
     * @param resource $ch curl会话的句柄
     *
     * @return boolean
     */
    static public function add_curl($k, $ch) {
        self::_multi_init();

        //添加curl句柄
        $ret = curl_multi_add_handle(self::$mh, $ch);
        if ($ret != 0) {//添加失败
            return false;
        }

        //若原来有相同$k,则删除,以便覆盖之
        if (isset(self::$arr_ch[$k])) {
            curl_multi_remove_handle(self::$mh, self::$arr_ch[$k]);//移除原curl句柄
            curl_close(self::$arr_ch[$k]);//关闭原curl会话
            unset(self::$arr_ch[$k]);//删除原$k
        }
        self::$arr_ch[$k] = $ch;

        return true;
    }

    /**
     * 执行批量请求,返回批量数据。原设置的k与其结果一一对应
     *
     * @param array $arr_ch 可选参数。key-curl句柄相对应的列表,用于批量设置curl句柄
     *
     * @return array
     */
    static public function multi_exec(array $arr_ch = array()) {
        $data = array();

        //批量添加curl会话句柄
        foreach ($arr_ch as $k => $ch) {
            self::add_curl($k, $ch);
        }

        //无批量执行句柄,返回空数组
        if (is_null(self::$mh)) {
            return $data;
        }

        //执行
        do {
            $mrc = curl_multi_exec(self::$mh,$active);
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
        while ($active && $mrc == CURLM_OK)
        {
            if (curl_multi_select(self::$mh) != -1)
            {
                do {
                    $mrc = curl_multi_exec(self::$mh, $active);
                } while ($mrc == CURLM_CALL_MULTI_PERFORM);
            }
        }
        //获取返回结果
        foreach (self::$arr_ch as $k => $ch) {
            $data[$k] = curl_multi_getcontent($ch);
            curl_multi_remove_handle(self::$mh, $ch);//移除句柄
            curl_close($ch);//关闭会话
        }
        curl_multi_close(self::$mh);//关闭批量会话

        //清理数据,恢复初始状态,为下一次使用做好准备
        self::_clear();

        return $data;
    }
}


这工具本质是发起并行请求,但若请求的自己定义的特殊接口,完全可以实现php伪多线程,进行某些数据的并行处理。

如自定义一个db查询接口,参数是sql(当然还有一下其它安全验证的参数等),返回值是查询结果。然后使用这个curl并行请求这个接口,那实现多条sql语句同时查询的功能。

并行查询数据库只是一个简单的例子,原则上所有不相互依赖的业务逻辑,都可以使用这种方法转为并行处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值