gpt4 book ai didi

php - 使用 PHP 并行下载页面

转载 作者:可可西里 更新时间:2023-11-01 12:50:04 24 4
gpt4 key购买 nike

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

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

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

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

我的问题是

  • 如何异步调用此类下载器,我不希望我的主脚本等到下载器完成。
  • 存储下载数据的任何位置,例如共享内存。当然,数据库除外。
  • 数据在存储和检索时有可能损坏,如何避免?
  • 另外,如果有人有更好的计划,请指导我。

最佳答案

当我听说有人使用 curl_multi_exec 时,通常结果是他们只是用 100 个 url 加载它,然后等待所有完成,然后处理所有这些,然后从下一个 100 个 url 重新开始......怪我,我也是这样做的,但后来我发现可以在某些事情仍在进行时删除/添加 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 实际上属于单独的类,而不是 Controller 或模型的实例。他们只处理设置 cURL 选项、解析响应并调用给定的回调 onComplete。使用这种结构,新请求将在池中的某些内容完成后立即开始。

当然,如果不仅检索需要时间而且处理也需要时间,那么它并不能真正为您节省时间……而且这不是真正的并行处理。但我仍然希望它有所帮助。 :)

附言对我做了个把戏。 :) 现在使用 50 个连接池可在 3-4 分钟内完成一次 8 小时的工作。无法形容那种感觉。 :) 我真的不希望它按计划工作,因为使用 PHP 它很少能完全按预期工作......就像“好的,希望它至少在一个小时内完成......哇......等等...... . 已经?!8-O”

关于php - 使用 PHP 并行下载页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9233356/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com