使用PHP并行下载页面

我必须废弃一个网站,我需要获取多个URL,然后逐个处理它们.目前的过程有点像这样.

我从此页面获取基本URL并获取所有辅助URL,然后为每个辅助URL我获取该URL,处理找到的页面,下载一些照片(这需要相当长的时间)并将此数据存储到数据库,然后获取下一个URL并重复这个过程.

在这个过程中,我认为我在每次迭代开始时浪费一些时间来获取辅助URL.所以我试图在处理第一次迭代时并行获取下一个URL.

我想到的解决方案是,从主进程调用PHP脚本,比如下载器,它将下载所有URL(使用curl_multi或wget)并将它们存储在某个数据库中.

我的问题是

>如何异步调用这样的downloder,我不希望我的主脚本等到downloder完成.
>存储下载数据的任何位置,例如共享内存.当然,除了数据库.
>存储和检索时数据是否有可能被破坏,如何避免这种情况?
>另外,如果有人有更好的计划,请指导我.

当我听到有人使用curl_multi_exec时,通常会发现他们只是用100个网址加载它,然后在完成后等待,然后全部处理它们,然后用接下来的100个网址重新开始…怪我,我是这样做,但后来我发现有可能在某些事情仍在进行时删除/添加curl_multi的句柄,并且它确实节省了大量时间,特别是如果你重用已经打开的连接.我写了一个小型库来处理带回调的请求队列;我当然不是在这里发布完整版本(“小”仍然是相当多的代码),但这里有一个简化版本,主要给你一般的想法:
public function launch() {
    $channels = $freeChannels = array_fill(0,$this->maxConnections,NULL);
    $activeJobs = array();
    $running = 0;
    do {
        // pick jobs for free channels:
        while ( !(empty($freeChannels) || empty($this->jobQueue)) ) {
            // take free channel,(re)init curl handle and let
            // queued object set options
            $chId = key($freeChannels);
            if (empty($channels[$chId])) {
                $channels[$chId] = curl_init();
            }
            $job = array_pop($this->jobQueue);
            $job->init($channels[$chId]);
            curl_multi_add_handle($this->master,$channels[$chId]);
            $activeJobs[$chId] = $job;
            unset($freeChannels[$chId]);
        }
        $pending = count($activeJobs);

        // launch them:
        if ($pending > 0) {
            while(($mrc = curl_multi_exec($this->master,$running)) == CURLM_CALL_MULTI_PERFORM);
                // poke it while it wants
            curl_multi_select($this->master);
                // wait for some activity,don't eat cpu
            while ($running < $pending && ($info = curl_multi_info_read($this->master))) {
                // some connection(s) finished,locate that job and run response handler:
                $pending--;
                $chId = array_search($info['handle'],$channels);
                $content = curl_multi_getcontent($channels[$chId]);
                curl_multi_remove_handle($this->master,$channels[$chId]);
                $freeChannels[$chId] = NULL;
                    // free up this channel
                if ( !array_key_exists($chId,$activeJobs) ) {
                    // impossible,but...
                    continue;
                }
                $activeJobs[$chId]->onComplete($content);
                unset($activeJobs[$chId]);
            }
        }
    } while ( ($running > 0 && $mrc == CURLM_OK) || !empty($this->jobQueue) );
}

在我的版本中,$jobs实际上是单独的类,而不是控制器或模型的实例.他们只处理设置cURL选项,解析响应并调用给定的回调onComplete.
使用此结构,只要池中的某些内容完成,新请求就会立即启动.

当然,如果不只是检索需要时间而且处理也不会真正拯救你……而且它并不是真正的并行处理.但我仍然希望它有所帮助.

相关文章

Hessian开源的远程通讯,采用二进制 RPC的协议,基于 HTTP 传输。可以实现PHP调用Java,Python,C#等多语...
初识Mongodb的一些总结,在Mac Os X下真实搭建mongodb环境,以及分享个Mongodb管理工具,学习期间一些总结...
边看边操作,这样才能记得牢,实践是检验真理的唯一标准.光看不练假把式,光练不看傻把式,边看边练真把式....
在php中,结果输出一共有两种方式:echo和print,下面将对两种方式做一个比较。 echo与print的区别: (...
在安装好wampServer后,一直没有使用phpMyAdmin,今天用了一下,phpMyAdmin显示错误:The mbstring exte...
变量是用于存储数据的容器,与代数相似,可以给变量赋予某个确定的值(例如:$x=3)或者是赋予其它的变...