Je travaille sur une application Web a PHP) et j’ai besoin d’effectuer certaines opérations réseau dans la requête, telle que récupérer une personne du serveur distant en fonction de la demande de l’utilisateur.
Est-il possible de simuler un comportement asynchrone dans PHP étant donné que je dois transmettre des données à une fonction et qu'il nécessite également une sortie.
Mon code est comme:
<?php
$data1 = processGETandPOST();
$data2 = processGETandPOST();
$data3 = processGETandPOST();
$response1 = makeNetworkCall($data1);
$response2 = makeNetworkCall($data2);
$response3 = makeNetworkCall($data3);
processNetworkResponse($response1);
processNetworkResponse($response2);
processNetworkResponse($response3);
/*HTML and OTHER UI STUFF HERE*/
exit;
?>
Chaque opération réseau prend environ 5 secondes, ce qui ajoute 15 secondes au temps de réponse de mon application étant donné que je fais 3 demandes.
La fonction makeNetworkCall () effectue simplement une requête HTTP POST).
Le serveur distant est une API tierce donc je n’ai aucun contrôle là-bas.
PS: S'il vous plaît ne répondez pas en donnant des suggestions sur AJAX ou autres choses. Je cherche actuellement si je peux le faire avec PHP peut être avec une extension C++ ou quelque chose comme ca.
De nos jours, il vaut mieux utiliser files d'attente que les threads (pour ceux qui n'utilisent pas Laravel il y a des tonnes d'autres implémentations sur le marché comme celui-ci =).
L’idée de base est que votre script original PHP place les tâches ou les travaux en file d’attente. Ensuite, les travailleurs de la file d’attente s’exécutent ailleurs, retirent les tâches de la file d’attente et les traitent indépendamment du code PHP d'origine. .
Les avantages sont:
Je n'ai pas de réponse directe, mais vous voudrez peut-être examiner ces choses:
job
terminé, insérez un nouveau travail décrivant le travail à effectuer pour traiter le corps de réponse HTTP mis en cache.cURL va être votre seul véritable choix ici (soit cela, soit en utilisant des sockets non bloquants et une logique personnalisée).
Ce lien devrait vous envoyer dans la bonne direction. Il n’existe pas de traitement asynchrone en PHP, mais si vous essayez de faire plusieurs requêtes Web simultanément, cURL multi s’occupe de cela pour vous.
Je pense que si le HTML et les autres éléments de l'interface utilisateur nécessitent que les données soient renvoyées, il ne sera pas possible de les asynchroniser.
Je crois que la seule façon de faire cela dans PHP serait de consigner une demande dans une base de données et de faire vérifier chaque cron, ou d'utiliser quelque chose comme le traitement de la file d'attente Gearman, ou peut-être exec () a processus de ligne de commande
En attendant, votre page php devra générer du HTML ou du JS qui le rechargera toutes les quelques secondes pour vérifier sa progression, pas idéal.
Pour éviter ce problème, combien de demandes différentes attendez-vous? Pourriez-vous tous les télécharger automatiquement toutes les heures environ et les sauvegarder dans une base de données?
Il existe également http v2 qui est un wrapper pour curl. Peut être installé via pecl.
Je pense qu'un peu de code sur la solution cURL est nécessaire ici, je vais donc partager le mien (il a été écrit en mélangeant plusieurs sources comme le PHP Manuel et commentaires).
Il fait des requêtes HTTP parallèles (domaines dans $aURLs
) et imprimez les réponses une fois chacune complétée (et les stockez dans $done
pour d'autres utilisations possibles).
Le code est plus long que nécessaire en raison de la partie d'impression en temps réel et de l'excès de commentaires, mais n'hésitez pas à modifier la réponse pour l'améliorer:
<?php
/* Strategies to avoid output buffering, ignore the block if you don't want to print the responses before every cURL is completed */
ini_set('output_buffering', 'off'); // Turn off output buffering
ini_set('zlib.output_compression', false); // Turn off PHP output compression
//Flush (send) the output buffer and turn off output buffering
ob_end_flush(); while (@ob_end_flush());
Apache_setenv('no-gzip', true); //prevent Apache from buffering it for deflate/gzip
ini_set('zlib.output_compression', false);
header("Content-type: text/plain"); //Remove to use HTML
ini_set('implicit_flush', true); // Implicitly flush the buffer(s)
ob_implicit_flush(true);
header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
$string=''; for($i=0;$i<1000;++$i){$string.=' ';} output($string); //Safari and Internet Explorer have an internal 1K buffer.
//Here starts the program output
function output($string){
ob_start();
echo $string;
if(ob_get_level()>0) ob_flush();
ob_end_clean(); // clears buffer and closes buffering
flush();
}
function multiprint($aCurlHandles,$print=true){
global $done;
// iterate through the handles and get your content
foreach($aCurlHandles as $url=>$ch){
if(!isset($done[$url])){ //only check for unready responses
$html = curl_multi_getcontent($ch); //get the content
if($html){
$done[$url]=$html;
if($print) output("$html".PHP_EOL);
}
}
}
};
function full_curl_multi_exec($mh, &$still_running) {
do {
$rv = curl_multi_exec($mh, $still_running); //execute the handles
} while ($rv == CURLM_CALL_MULTI_PERFORM); //CURLM_CALL_MULTI_PERFORM means you should call curl_multi_exec() again because there is still data available for processing
return $rv;
}
set_time_limit(60); //Max execution time 1 minute
$aURLs = array("http://domain/script1.php","http://domain/script2.php"); // array of URLs
$done=array(); //Responses of each URL
//Initialization
$aCurlHandles = array(); // create an array for the individual curl handles
$mh = curl_multi_init(); // init the curl Multi and returns a new cURL multi handle
foreach ($aURLs as $id=>$url) { //add the handles for each url
$ch = curl_init(); // init curl, and then setup your options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // returns the result - very important
curl_setopt($ch, CURLOPT_HEADER, 0); // no headers in the output
$aCurlHandles[$url] = $ch;
curl_multi_add_handle($mh,$ch);
}
//Process
$active = null; //the number of individual handles it is currently working with
$mrc=full_curl_multi_exec($mh, $active);
//As long as there are active connections and everything looks OK…
while($active && $mrc == CURLM_OK) { //CURLM_OK means is that there is more data available, but it hasn't arrived yet.
// Wait for activity on any curl-connection and if the network socket has some data…
if($descriptions=curl_multi_select($mh,1) != -1) {//If waiting for activity on any curl_multi connection has no failures (1 second timeout)
usleep(500); //Adjust this wait to your needs
//Process the data for as long as the system tells us to keep getting it
$mrc=full_curl_multi_exec($mh, $active);
//output("Still active processes: $active".PHP_EOL);
//Printing each response once it is ready
multiprint($aCurlHandles);
}
}
//Printing all the responses at the end
//multiprint($aCurlHandles,false);
//Finalize
foreach ($aCurlHandles as $url=>$ch) {
curl_multi_remove_handle($mh, $ch); // remove the handle (assuming you are done with it);
}
curl_multi_close($mh); // close the curl multi handler
?>