Kiedy słyszę, że ktoś używa curl_multi_exec, zwykle się po prostu ładuje, powiedzmy, 100 adresów URL, a następnie zaczekaj, aż wszystko będzie kompletne, a następnie przetwórz je wszystkie, a następnie zacznij od następnych 100 adresów URL ... ja też tak robiłem, ale potem dowiedziałem się, że możliwe jest usuwanie/dodawanie uchwytów do curl_multi, gdy coś jest nadal w toku, i to naprawdę oszczędza dużo czasu, szczególnie jeśli ponownie wykorzystujesz już otwarte połączenia. Napisałem małą bibliotekę do obsługi kolejki żądań z oddzwanianiem; Nie jestem opublikowania pełnej wersji tutaj oczywiście („mały” jest jeszcze trochę kodu), ale tutaj jest uproszczoną wersją Najważniejsze, aby dać Ci ogólne pojęcie:
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));
}
W mojej wersji $ zadania są w rzeczywistości oddzielną klasą, a nie instancjami kontrolerów lub modeli. Po prostu obsługują ustawianie opcji cURL, analizowanie odpowiedzi i wywoływanie danego wywołania zwrotnego onComplete. Dzięki tej strukturze nowe wnioski zaczną się, gdy tylko coś z basenu się skończy.
Oczywiście to naprawdę nie oszczędza, jeśli nie tylko pobieranie zajmuje trochę czasu, ale również przetwarzanie ... I to nie jest prawdziwa obsługa równoległa. Ale wciąż mam nadzieję, że to pomaga. :)
P.S. zrobiłem dla mnie sztuczkę. :) Po 8-godzinnej pracy kończy się w 3-4 minutach przy użyciu puli 50 połączeń. Nie potrafię opisać tego uczucia. :) Nie spodziewałem się, że będzie działał zgodnie z planem, ponieważ z PHP rzadko działa dokładnie tak, jak powinno ... To było jak "ok, mam nadzieję, że skończy się co najmniej godzinę ... Co ... Poczekaj ... Już teraz ?! 8-O "
PHP nie jest tak naprawdę zaprojektowane do uruchamiania wielu procesów. Dlaczego nie spojrzeć na taki język jak Python, aby to osiągnąć? – afuzzyllama
@afuzzyllama To tylko podmoduł, cały projekt jest w PHP –
[nodejs] (http://nodejs.org) byłby idealny do tego. – Xeoncross