PROJET AUTOBLOG


le hollandais volant

Site original : le hollandais volant

⇐ retour index

Mise à jour

Mise à jour de la base de données, veuillez patienter...

[PHP] Faire plusieurs requêtes HTTP simultanées avec cURL

mardi 20 mai 2014 à 21:21
two elephants Toujours en développement de mon lecteur RSS en PHP, je me suis heurté au problème de la mise à jour des 154 flux auquel je suis abonné. Si le file_get_contents() fonctionne avec les URL, il ne peut les télécharger que les uns après les autres. Ainsi, même en ne mettant qu’un délai d’attente d’une seconde, la mise à jour prendrait au minimum 2 minutes 34 secondes. C’est bien trop long.

Une solution aurait pu être de faire 154 requêtes depuis les navigateur, pour ouvrir 154 instances de file_get_contents(), mais ça me semblait trop lourd.

La meilleure solution est à mon avis d’utiliser le module curl : lui, il peut faire 154 requêtes simultanées, et la durée de l’opération totale sera simplement la durée de la plus longue des requêtes et non la somme de toutes les requêtes. Avec cette méthode, je met à jour tous mes flux en moins d’une minute, toutes opérations incluses.

En pratique, pour récupérer le contenu de plusieurs URL, ça se présente comme suit.

On initialise une liste de sessions curl « $multihandler » : chacune correspondra à une instance de curl qui ira se connecter à une URL :
// init multi handler
$multihandler = curl_multi_init();
$handlers = $result = array();

On peuple la liste des sessions : chaque session est initialisée individuellement (avec une option CURLOPT_RETURNTRANSFER qui force curl à retourner le contenu plutôt que de l’afficher) puis on ajoute la session $handler[$i] à la liste des sessions $multihandler
// init each url
foreach ($urls as $i) {
	$handlers[$i] = curl_init($i);
	curl_setopt($handlers[$i], CURLOPT_RETURNTRANSFER, TRUE);
	curl_multi_add_handle($multihandler, $handlers[$i]);
}

Il n’y a plus qu’à établir toutes les connexions aux URL et télécharger les données.
Le $pendingConnex est une variable donnée par curl qui donne le nombre de connexions actives. Ce nombre diminuera progressivement jusqu’à zéro quand toutes les URL auront été téléchargées.

Les 10 ms d’attente sont là pour éviter que PHP ne fasse trop de tests, et permet de réduire la charge serveur (si on ne le met pas, la charge serveur explose — une méthode plus propre, mais dont le gain par rapport au sleep() n’est pas énorme est visible dans la doc).
10ms, pour un temps d’exécution de 10 seconde sur un processeur qui fait une boucle par nanoseconde (proc à 1 GHz) permet de réduire le nombre d’itérations par un facteur 10'000'000, ce qui est colossal : le serveur a dix millions de fois moins de puissance à allouer.

Dans mon lecteur RSS, je mets dans cette boucle do/while le code qui m’affiche à intervalle régulier le nombre de requêtes restantes.

// exec connexions + download
do {
	curl_multi_exec($multihandler, $pendingConnex);
	usleep(10000); // 10 ms
} while ($pendingConnex > 0);

À ce stade, les requêtes sont faites, les données récupérées en mémoire.
Il suffit de les parser et de les récupérer dans le tableau $result. Ce tableau contiendra les données en valeur et les URL en clés :

// parse responses
foreach ($urls as $i) {
	$result[] = curl_multi_getcontent($handers[$i]);
}

Le code ci-dessus devrait être suffisant.
Néanmoins, je conseille d’ajouter quelques options, avec curl_setopt() :

image de Jim Frost

Feed is invalid - XML error: --------^ Fatal Error 76: Opening and ending tag mismatch: link line 13 and head Line: 93 Column: 8 - -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------^ Fatal Error 68: xmlParseEntityRef: no name Line: 147 Column: 1805 - ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------^ Fatal Error 68: xmlParseEntityRef: no name Line: 147 Column: 2032 - --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------^ Fatal Error 68: xmlParseEntityRef: no name Line: 147 Column: 2300 - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------^ Fatal Error 23: EntityRef: expecting ';' Line: 147 Column: 2307 - --------^ Fatal Error 76: Opening and ending tag mismatch: meta line 5 and html Line: 150 Column: 8 - -^ Fatal Error 77: Premature end of data in tag meta line 4 Line: 151 Column: 1 - -^ Fatal Error 77: Premature end of data in tag head line 3 Line: 151 Column: 1 - -^ Fatal Error 77: Premature end of data in tag html line 2 Line: 151 Column: 1