来源:http://www.jb51.net/article/42826.htm

给各位介绍一下Curl多线程实例与原理。不对之处请指教
相信许多人对php手册中语焉不详的curl_multi一族的函数头疼不已,它们文档少,给的例子 更是简单的让你无从借鉴,我也曾经找了许多网页,都没见一个完整的应用例子。
curl_multi_add_handle 
curl_multi_close 
curl_multi_exec 
curl_multi_getcontent 
curl_multi_info_read 
curl_multi_init 
curl_multi_remove_handle 
curl_multi_select 
一般来说,想到要用这些函数时,目的显然应该是要同时请求多个url,而不是一个一个依次请求,否则不如自己循环去调curl_exec好了。
步骤总结如下:
第一步:调用curl_multi_init
第二步:循环调用curl_multi_add_handle
这一步需要注意的是,curl_multi_add_handle的第二个参数是由curl_init而来的子handle。
第三步:持续调用curl_multi_exec
第四步:根据需要循环调用curl_multi_getcontent获取结果
第五步:调用curl_multi_remove_handle,并为每个字handle调用curl_close
第六步:调用curl_multi_close 
这里有PHP手册上的例子:

复制代码代码如下:

<?php 
// 创建一对cURL资源 
$ch1 = curl_init(); 
$ch2 = curl_init();

// 设置URL和相应的选项 
curl_setopt($ch1, CURLOPT_URL, "http://www.jb51.net/"); 
curl_setopt($ch1, CURLOPT_HEADER, 0); 
curl_setopt($ch2, CURLOPT_URL, "http://www.php.net/"); 
curl_setopt($ch2, CURLOPT_HEADER, 0);

// 创建批处理cURL句柄 
$mh = curl_multi_init();

// 增加2个句柄 
curl_multi_add_handle($mh,$ch1); 
curl_multi_add_handle($mh,$ch2);

$active = null; 
// 执行批处理句柄 
do { 
    $mrc = curl_multi_exec($mh, $active); 
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active && $mrc == CURLM_OK) { 
    if (curl_multi_select($mh) != -1) { 
        do { 
            $mrc = curl_multi_exec($mh, $active); 
        } while ($mrc == CURLM_CALL_MULTI_PERFORM); 
    } 
}

// 关闭全部句柄 
curl_multi_remove_handle($mh, $ch1); 
curl_multi_remove_handle($mh, $ch2); 
curl_multi_close($mh); 
?>

整个使用过程差不多就是这样,但是,这个简单代码有个致命弱点,就是在do循环的那段,在整个url请求期间是个死循环,它会轻易导致CPU占用100%。
现在我们来改进它,这里要用到一个几乎没有任何文档的函数curl_multi_select了,虽然C的curl库对select有说明,但是,php里的接口和用法确与C中有不同。
把上面do的那段改成下面这样:

复制代码代码如下:

do { 
                        $mrc = curl_multi_exec($mh,$active); 
                 } while ($mrc == CURLM_CALL_MULTI_PERFORM); 
                while ($active and $mrc == CURLM_OK) { 
                        if (curl_multi_select($mh) != -1) { 
                                do { 
                                        $mrc = curl_multi_exec($mh, $active); 
                                 } while ($mrc == CURLM_CALL_MULTI_PERFORM); 
                         } 
                 }

因为$active要等全部url数据接受完毕才变成false,所以这里用到了curl_multi_exec的返回值判断是否还有数据,当有数据的时候就不停调用curl_multi_exec,暂时没有数据就进入select阶段,新数据一来就可以被唤醒继续执行。这里的好处就是CPU的无谓消耗没有了。
另外:还有一些细节的地方可能有时候要遇到:
控制每一个请求的超时时间,在curl_multi_add_handle之前通过curl_setopt去做:
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); 
判断是否超时了或者其他错误,在curl_multi_getcontent之前用:curl_error($conn[$i]);

本类的特点:
运行非常稳定。
设置一个并发就会始终以这个并发数进行工作,即使通过回调函数添加任务也不影响。
CPU占用极低,绝大部分CPU消耗在用户的回调函数上。
内存利用率高,任务数量较多(15W个任务占用内存会超过256M)可以使用回调函数添加任务,个数自定。
能够最大限度的占用带宽。
链式任务,比如一个任务需要从多个不同的地址采集数据,可以通过回调一气呵成。
能够对CURL错误进行多次尝试,次数自定(大并发一开始容易产生CURL错误,网络状况或对方服务器稳定性也有可能产生CURL错误)。
回调函数相当灵活,可以多种类型任务同时进行(比如下载文件,抓取网页,分析404可以在一个PHP进程中同时进行)。
可以非常容易的定制任务类型,比如检查404,获取redirect的最后url等。
可以设置缓存,挑战产品节操。
不足:
不能充分利用多核CPU(可以开多个进程解决,需要自己处理任务分割等逻辑)。
最大并发500(或512?),经过测试是CURL 内部限制,超过最大并发会导致总是返回失败。
目前没有断点续传功能。
目前任务是原子性的,不能对一个大文件分为几部分分别开线程下载。

PHP Curl多线程原理实例详解相关推荐

  1. linux c多进程多线程,linux下的C\C++多进程多线程编程实例详解

    linux下的C\C++多进程多线程编程实例详解 1.多进程编程 #include #include #include int main() { pid_t child_pid; /* 创建一个子进程 ...

  2. python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解

    2019独角兽企业重金招聘Python工程师标准>>> 1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过 ...

  3. c#多线程thread实例详解

    1. Thread线程启动 由于ThreadStart是一个委托,所以可以简化写法 static void Main(string[] args){Console.WriteLine("-- ...

  4. java linkedlist实例_Java Linkedlist原理及实例详解

    这篇文章主要介绍了Java Linkedlist原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 定义:linkedlist属于链表结构 ...

  5. wxpython多线程 假死_wxpython多线程防假死与线程间传递消息实例详解

    wxpython中启用线程的方法,将GUI和功能的执行分开. 网上关于python多线程防假死与线程传递消息是几年前的,这里由于wxpython和threading模块已经更新最新,因此给出最新修改代 ...

  6. sort函数怎么用mysql_实例详解sort()函数的原理和使用方法

    本文主要为大家分享一篇实例详解sort()函数的原理和使用方法,具有很好的参考价值,希望对大家有所帮助.一起跟随小编过来看看吧,希望能帮助到大家. sort()方法就是对数组按照一定的条件进行排序. ...

  7. redis队列优先级java实现_Redis 实现队列原理的实例详解

    Redis 实现队列原理的实例详解 场景说明: ·用于处理比较耗时的请求,例如批量发送邮件,如果直接在网页触发执行发送,程序会出现超时 ·高并发场景,当某个时刻请求瞬间增加时,可以把请求写入到队列,后 ...

  8. php 断点续传 暂停,PHP 断点续传实例详解

    在做一个案例,要给客户端做断点续传的服务, 断点续传主要是HTTP协议中的Content-Range报头.其理解如下: Content-Range:响应资源的范围.可以在多次请求中标记请求的资源范围, ...

  9. Java并发编程最佳实例详解系列

    Java并发编程最佳实例详解系列: Java并发编程(一)线程定义.状态和属性 Java并发编程(一)线程定义.状态和属性 线程是指程序在执行过程中,能够执行程序代码的一个执行单元.在java语言中, ...

最新文章

  1. 使用tmpfs缓存文件提高性能
  2. 不上市就等死?AI故事难讲,豪门盛宴背后的“血”与“泪”
  3. GUN sed高级用法,sed脚本编写
  4. 打开git命令窗口_用动图的形式打开 10 大 Git 命令?
  5. python各个解释器的用途-【Python面试】 说说Python解释器种类以及特点?
  6. html元素li移动动态效果
  7. 《以前工作中的三大痛点,只因他们没学Python》
  8. k8s组件说明:主要组件统一说明
  9. 树莓派+神经计算棒2实时人脸检测
  10. 从头开始敲代码之《从BaseApplication/Activity开始(二)》
  11. 华为云薛浩:媒体业务进入全面云化时代,云原生成为必然选择
  12. 【英语学习】【Level 08】U02 Movie Time L2 In black and white
  13. Emacs编辑Nginx
  14. 【Python读文件】'gbk' codec can't decode byte 0xb1 in position 5: illegal multibyte sequence
  15. windows执行命令来运行loadrunner录制好的脚本(收藏)
  16. Bz1621.lzh二进制编辑器下载
  17. nginx反向代理与正向代理
  18. 逻辑回归分类——信用卡诈骗检测!这才是干货!
  19. strlen函数原理
  20. Stockfolio 1.5 特别版 Mac 实时股票行情炒股软件

热门文章

  1. 1.18.5.流式概念、动态表(Dynamic Table)、DataStream上的关系查询、动态表 连续查询(Continuous Query)、在流上定义表、处理时间
  2. BeautifulSoup children descendants对比
  3. odps结合mysql统计
  4. java 博客系统_讲解开源项目:5分钟搭建私人Java博客系统
  5. php中函数声明的方法,PHP中的函数声明与使用
  6. 基于深度学习的医学图像分割综述
  7. faster-rcnn中添加Mask中的RoiAlign层,使回归框更精确( roi_align_layer.cu:240] Check failed: error == cudaSuccess *)
  8. Kotlin 4 构造,对象,修饰符,关键字,委托
  9. MVC根据CheckBox的Value值选中对应的复选框及获取选中的Value值
  10. webservice gsoap 小记