Когда я слышу, что кто-то использует curl_multi_exec, обычно получается, что он просто загружает его, скажем, 100 URL-адресами, затем ждет, когда все будет завершено, и затем обрабатывает их все, а затем начинает заново со следующими 100 URL-адресами ... Вини Я тоже так делал, но потом обнаружил, что можно удалить / добавить маркеры в curl_multi, пока что-то еще происходит, и это действительно экономит много времени, особенно если вы повторно используете уже открытые соединения. Я написал небольшую библиотеку для обработки очереди запросов с обратными вызовами; Конечно, я не публикую здесь полную версию ("small" - это все еще немного кода), но вот упрощенная версия, чтобы дать вам общее представление:
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.
С этой структурой новые запросы начнутся, как только что-то из пула завершится.
Конечно, это на самом деле не спасет вас, если не просто получение требует времени, но и обработки ... И это не настоящая параллельная обработка. Но я все еще надеюсь, что это поможет. :)
P.S. сделал трюк для меня. :) Однажды 8-часовая работа теперь выполняется за 3-4 минуты, используя пул из 50 соединений. Не могу описать это чувство. :) Я не ожидал, что он будет работать так, как планировалось, потому что с PHP он редко работает точно так, как предполагалось ... Это было похоже на "хорошо, надеюсь, что оно завершится как минимум через час ... Wha ... Подождите ... . Уже ?! 8-О "