文档章节

curl_multi在抓取数据中的并发实现

 恒心
发布于 2013/12/12 19:16
字数 1451
阅读 5620
收藏 11

h3. 背景



       在网校最初时,接入的网校就几家,而且课程数据量较小,为快速开发上线,就采取逐个遍历课程数据源,进行抓取,然后解析数据并处理,存入到数据库中。但是随着网校的接入, 且为展示更多课程数据信息,字段内容又不断调整,导致请求的数据变大,抓取的时间变得延长,顺序的处理流程,又容易造成如果某个数据源出错,导致剩下的网校课程数据无法抓取。
      恰逢网校要开发详情页,需要调整字段,引入更多数据,抓取的当前框架有些耦合,特别是网络处理这些,不能支持多并发,担心随着数据量的增大,处理完后,会严重导致不断调整cron中的其他业务脚本,毕竟依赖最新的数据,如删除过 期的数据,向引擎推送数据等,未来是打算整合这些脚本,但提高数据抓取与处理的性能,还是必须做的。


h3. 数据依赖与并发


      网校目前的各个数据源都是来自于各个教育机构,因而没有依赖性,这就在抓取数据时,方便并发处理;如果网校的数据源存在依赖,特别是某条数据源的请求依赖上次某条数据源的处理结果,则将不得不采用串行处理。即使并发,也可并发 请求完所有数据,然后再对数据进行处理,如图



      但是会发现,这种方式并不能利用客户端等待服务端数据到达的空隙,更好的处理是,当某个数据源的数据到达时,就能立即处理,而不是等待所有的数据源的数据到达时,再逐个处理数据。在目前的网校课程数据源中,不同教育机构给出的课程 数差异很大,有些数据可能要持续两三分钟,才能请求完,而有些数据几秒内就可到达,因而谁到处理谁,能更好利用CPU。


h3. 并发的实现



       在当前PHP并发的方法中,可以使用curl_multi_*系列的方法,也可利用其它人开发的专用并发框架,如鸟哥写的yar,考虑到学习成本与资源,就直接采用curl_multi_*方法,而且本身也有封装好的专门用于“谁到处理谁”的框架RollingCurl,
提供更好的网络控制处理,并提供相关的DEMO,但核心代码依然是curl_multi_*系列方法的处理:
{code:java}
  do {
            while (($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM) ;
            if ($execrun != CURLM_OK)
                break;
            // a request was just completed -- find out which one
            while ($done = curl_multi_info_read($master)) {
                // get the info and content returned on the request
                ...


                // send the return values to the callback function.
                ...


                // start a new request (it's important to do this before removing the old one)
                ...
                }


                // remove the curl handle that just completed
                curl_multi_remove_handle($master, $done['handle']);
            }


            // Block for data in / output; error handling is done by curl_multi_exec
            if ($running)
                curl_multi_select($master, $this->timeout);
        } while ($running);
{code}


       当调用curl_multi_add_handle添加curl句柄时,就会进入do-while大循环代码,首先执行curl_multi_exec,但是此方法,在do-while循环中被多次调用,PHP文档给此方法的解释是“处理在栈中的每一个句柄。
无论该句柄需要读取或写入数据都可调用此方法。”,也就是说第一次调用此方法是用于发出HTTP请求数据,当栈中的句柄还有数据需要传送时,就会返回 CURLM_CALL_MULTI_PERFORM,当返回CURLM_OK只是意味着数据传送完毕或者没有数据 可传送。此方法是不阻塞的,也就是说一旦栈中某个或多个curl句柄有数据读取或者写入,就可以调用此方法传送数据,并立即返回栈中句柄的活动状态。
       url_multi_info_read方法是检查批处理句柄中某次传送数据结束的状态(当curl_multi_exec调用返回CURLM_OK),可能上次并没有数据可传送,则队列中并没有任何消息,则就会返回false;可能传送数
据出现错误,消息队列就会有某个批处理句柄出错的信息,当数据成功完成时,则返回的消息体中的msg字段值会为CURLMSG_DONE,其他值都不可用,表明出错。
       如果没有后面的curl_multi_select方法上述程序也能正常运行,但是就会发现整个程序处于不停空转中,毕竟网络传输数据占用时间还是蛮长的,每次调用curl_multi_exec可能都是立即返回CURLM_OK,然后执行
curl_multi_info_read,又立即返回false,如此继续。而调用curl_multi_select,就会等待直到多个SOCKET中的某个处于活跃状态,不然就处于阻塞状态,直到超时为止,就不会出现程序忙空转状态。
       在上述程序代码中,可以看到,当某次传送数据完成后,就会立即处理返回来的数据,而不是待所有句柄的请求数据都完成后,才继续处理数据,其实这种等待所有请求数据都完成时再处理的情形,也有很多应用场景,如某个页面的数据, 来自于多个源,只有组装在一起,才能渲染页面。到时只需要将调用curl_multi_info_read方法的那块代码移除,在do-while循环后添加数据处理的过程即可。


h5. 参考文献



[php curl document|http://www.php.net/manual/zh/ref.curl.php]
[rolling-curl|https://github.com/takinbo/rolling-curl]
[php-src|https://github.com/php/php-src]
[libcutl-multi API document|http://curl.haxx.se/libcurl/c/libcurl-multi.html]
[curl-src|https://github.com/bagder/curl]

© 著作权归作者所有

粉丝 0
博文 5
码字总数 5859
作品 0
朝阳
私信 提问
《CURL技术知识教程》系列分享专栏

《CURL技术知识教程》已整理成PDF文档,点击可直接下载至本地查阅 https://www.webfalse.com/read/201737.html 文章 PHP采集相关教程之一 CURL函数库 php中通过curl模拟登陆discuz论坛的实现...

开元中国2015
2018/11/06
0
0
《CURL技术知识教程》系列技术教程整理

《CURL技术知识教程》系列技术教程整理 有时间会不断更新,大家有什么好的推荐的可以在下面回复,我会酌情收录 1PHP采集相关教程之一 CURL函数库 2php中通过curl模拟登陆discuz论坛的实现代码...

开元中国2015
2015/05/07
470
0
php curl请求信息和返回信息设置代码实例,特别是在请求过程中存在重定向的时候获取请求返回头信息

在用curl抓取网页内容的时候,经常要知道,网页返回的请求头信息,和请求的相关信息,特别是在请求过程中存在重定向的时候获取请求返回头信息对分析请求内容很有帮助 下面就是一个请求中存在...

蜗牛奔跑
2015/06/26
0
0
php实现并发处理之curl篇

php在并发处理方面的确不如java好。但是也有一些方法可以实现并发处理。比如使用curl就可以实现url的并发请求。 看到网上有人说使用curl会导致阻塞,即所有的请求数据都获取完毕后一并返回,...

snowing1990
2016/03/29
29
0
PHP爬虫:百万级别知乎用户数据爬取与分析

这次抓取了110万的用户数据,数据分析结果如下: 开发前的准备 安装Linux系统(Ubuntu14.04),在VMWare虚拟机下安装一个Ubuntu; 安装PHP5.6或以上版本; 安装MySQL5.5或以上版本; 安装cur...

snowing1990
2016/04/06
92
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周日乱弹 —— 请务必让我分担他们的痛苦!

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @clouddyy :分享石元丈晴的单曲《Why》: 《Why》- 石元丈晴 手机党少年们想听歌,请使劲儿戳(这里) @一代码哥 :当他妈狗屁的程序员,天天...

小小编辑
36分钟前
98
4
php 遇到 No input file specified的解决方法

(一)IIS Noinput file specified 方法一:改PHP.ini中的doc_root行,打开ini文件注释掉此行,然后重启IIS 方法二: 请修改php.ini 找到 ; cgi.force_redirect = 1 去掉前面分号,把后面的1...

chenhongjiang
今天
9
0
MySQL 基础

一、常用命令 在命令行中,配置好环境变量后,通过cmd可以直接进入mysql命令行模式,同时列举几种常用命令 # 进入mysql数据库,密码可以先不写,打完-p后再输入,防止被别人看到mysql -u账...

华山猛男
今天
6
0
简单的博客系统(四)Django请求HTML页面视图信息--基于函数的视图

1. 编写用于查询数据的功能函数 应用目录 下的 views.py 文件通常用于保存响应各种请求的函数或类 from django.shortcuts import renderfrom .models import BlogArticles# Create your ...

ZeroBit
今天
6
0
用脚本将本地照片库批量导入到Day One中

因为目前iCloud 空间已经不足,其中95%都是照片,之前入手了DayOne,且空间没有限制,订阅费一年也不少,再加上DayOne作为一款日记App 也比较有名,功能方面最大的就是地理视图与照片视图,尤...

在山的那边
昨天
24
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部