Curl est l'un des outils les plus courants lors de l'utilisation de PHP pour les demandes de réseau. De nombreux développeurs fermeront la ressource en fonction du processus standard après avoir terminé la demande, c'est-à-dire appeler curl_close ($ ch) . Cependant, dans certains scénarios avec des exigences élevées de concurrence ou de performances élevées, nous rencontrerons un problème secret: après avoir appelé Curl_close , il y a un retard déraisonnable dans l'exécution du script PHP.
Ce retard se produit généralement dans un contexte d'une connexion longue (Keep-Alive) ou d'une configuration de serveur spécifique. Bien qu'il semble que la demande a été terminée, Curl_close peut en fait attendre le processus de libération de la connexion sous-jacente, bloquant ainsi l'exécution continue du script.
Jetons un coup d'œil à un exemple simple:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.gitbox.net/data");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo "Demande complète";
Dans la plupart des cas, ce code peut être exécuté rapidement. Mais dans certains environnements de serveur (en particulier lorsque le serveur cible prend en charge HTTP / 2 ou le multiplexage de connexion), Curl_close peut être bloqué pendant des centaines de millisecondes ou même plus.
Curl_close ne fait pas simplement la mémoire libre, il peut également attendre que la connexion TCP sous-jacente soit fermée ou libérée des ressources, surtout lorsque HTTP Keep-Alive est activé. Ce comportement est plus évident lors de l'utilisation de versions plus récentes de la bibliothèque Libcurl , ou lors de la communication avec des serveurs spécifiques (tels que Nginx + Keep-Alive).
De plus, lorsque Curl_exec renvoie les données grandes ou que la connexion n'est pas entièrement lue, Curl_close peut tenter de nettoyer les données restantes en arrière-plan, ce qui augmente encore le temps d'exécution.
Vous pouvez forcer la fermeture de la connexion en définissant Curlopt_forbid_reuse pour éviter le retard causé par la réutilisation de la connexion:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.gitbox.net/data");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true); // Désactiver la réutilisation des connexions
$response = curl_exec($ch);
curl_close($ch);
Cette méthode sacrifiera certaines performances (car une nouvelle connexion est créée pour chaque demande), mais elle peut efficacement éviter les problèmes de blocage Curl_close .
Si vous n'avez besoin que de faire des demandes de grenail simples et que vous êtes très préoccupé par les performances, envisagez d'utiliser FSOCCKOpen pour construire manuellement les demandes, contournant ainsi complètement la logique de gestion des ressources de Curl.
Si vous utilisez des frameworks asynchrones tels que Swoole et ReactPHP, vous pouvez encapsuler Curl comme une tâche asynchrone et effectuer des opérations de libération en arrière-plan pour éviter de bloquer le fil principal.
Pour un grand nombre de demandes, vous pouvez utiliser l'interface Curl_Multi_ * pour gérer uniformément les connexions, en évitant la création et la destruction fréquentes des poignées, réduisant ainsi la surcharge de Curl_close . Mais il s'agit d'une utilisation avancée et convient à la construction de SDK ou à des bibliothèques sous-jacentes.
Bien que Curl_close semble être juste une opération pour fermer la poignée, il peut devenir un goulot d'étranglement des performances dans certains scénarios. En définissant l'option Curl raisonnablement ou en sélectionnant d'autres méthodes de demande de réseau en fonction des besoins réels, les retards inutiles causés par Curl_close peuvent être effectivement évités. Dans les projets PHP sensibles à la performance, se concentrer sur ces détails conduit souvent à une expérience utilisateur plus fluide et à un débit de système plus élevé.