Accélérer vos scripts php grâce au multithreading
Ecrit par Maxime le Jeudi 2 septembre 2010 à 13:43 - Catégorie Scripts PHP
Lecteur de SeoBlackOut, Tiger m’a fait le plaisir de publier ce premier article qui je l’espère vous plaira. Nous avons mis en place dans ma boite qui crée des boutiques en ligne ce script qui permet de multithreader des scripts php.
Imaginez le cas suivant : Vous souhaitez créer un script qui extrait des données du web. Si vous êtes très BlackHat ce sera pour extraire des digg-likes et des blogs à spammer, ou comme chez Vaisonet ce sera plutôt un script pour faire des relevés de prix sur les boutiques en ligne des concurrents de vos clients … C’est toujours plus sympathique que de le faire à main.
Dans tous les cas, vous ne voulez par faire quelque chose d’agressif et vous temporisez le tout. Vous avez donc certainement quelque chose comme cela :
$sites = array('www.siteA.fr', 'www.siteB.fr', 'www.siteC.fr', ) foreach($sites as $site) { //Votre fonction d'extraction extraction($site); //La tempo pour passer sous les radars sleep(15); }
Si vous voulez accélérer les choses, le seul moyen est de lancer toutes les extractions en parallèle. C’est facile à faire avec peu de paramètre, mais remplacez 3 sites exemples par 30 à faire tous les jours, c’est vite pénible !
L’idée est donc d’exécuter chaque élément de la boucle foreach dans un thread distinct en même temps que les autres.
Mauvaise nouvelle, php ne sait pas vraiment faire cela, il faut utiliser autre chose. De nombreux langages le permettent : C, C++, Java, etc … J’ai choisi Python. C’est un langage qui n’est pas compilé, rapide à coder et vous le verrez facile à comprendre.
Mais je vois déjà une objection pointer à l’horizon : pourquoi ne pas tout coder en Python ? Ce serait clairement la solution la plus pertinente techniquement, je suis parfaitement d’accord. Mais dans les faits, les cordonniers sont les plus mal chaussés : on traine de vieux bouts de code php issu d’une ancienne application web, ou on fait des extractions plus complexe en Perl avec Talend par exemple.
Et oui, avec le script qui arrive, vous pourrez aussi multithreader des scripts Perl !
Bref, cet outil vous permettra de recycler vos vieux bouts de code
Préalable sur Python
Il vous faut Python 3 installé sur votre poste : http://www.python.org/
Python 3 contient un éditeur très commode : IDLE que je vous encourage à utiliser. Et deux astuces : attention à l’identation avec Python. Mettez l’extension py pour un script Python classique et pyw pour un script se lançant sans fenêtre. Je le recommande pour ce script.
Si vous souhaitez diffuser votre script Python et qu’il fonctionne sans avoir à installer Python, tournez vous vers py2exe (Utilisateurs avancés : imaginez ce que l’on peut faire en distribuant les calculs via un exe …).
Multithreader PHP grâce à Python
# Limititation : les threads d'utilisent qu'un coeur d'un processeur multicoeur # Ce n'est pas gênant pour l'utilisation escomptée, sachant que la puissance de # calcul n'est pas le facteur limitant, celui-ci étant la latence réseau. # Auteur : Maxime Varinard - Vaisonet - http://www.vaisonet.com # Vous pouvez librement ré-utiliser ce script, mais un petit backlink avec une belle # ancre de votre choix contenant e-commerce serait un beau remerciement ;) import threading, os from tkinter import * th = 0 def lancement(param): global th th = th + 1 # la ligne ci-dessous est à adapter pour lancer les bons programmes/scripts script = '"c:/Program Files/xampp/php/php.exe" c:/Users/Maxime/Desktop/sleep.php ' + param os.system(script) th = th - 1 # On peut lancer manuellement des scripts, hors boucle for (par exemple un script perl) a = threading.Thread(None, lancement, None, ('1',)) b = threading.Thread(None, lancement, None, ('5',)) a.start() b.start() # On lance la boucle des threads # Le tableau li contient les paramètres à passer au script. Il lancera en parallèle les scripts # avec les différents paramètres. li = ['www.siteA.fr', 'www.siteB.fr', 'www.siteC.fr'] for s in li: s = threading.Thread(None, lancement, None, (s,)) s.start() # Le thread qui surveille la fin d'exécution des autres threads # Permet de signaler la fin d'exécution des scripts lancés s'ils n'ont pas de fenêtres def alert(): global th while th > 0: # On ne fait rien continue fen = Tk() fen.title('Outils Vaisonet') tex = Label(fen, text='Les tâches sont terminées !', width=45, height=3) tex.pack() bou = Button(fen, text='Ok', command = fen.destroy) bou.pack() fen.mainloop() print("fini", th) EA = threading.Thread(None, alert, None) EA.start()
Le script est bien commenté, mais voici quelques explications complémentaires pour son intégration avec php. Il faut sortir la boucle foreach de votre script php pour l’intégrer dans le script Python. On appelle ensuite votre script php en ligne de commande. Cela veut donc dire qu’il faut savoir utiliser $argv pour passer le paramètre. Voici un exemple, mon fichier sleep.php de test
echo "toto" . $argv[1]; sleep(30);
Et si vraiment vous voulez tenter de faire du mutlithreading avec php, faites un tour du côté de stream_select.
La solution avec cURL pose parfois des problèmes, mais vous pouvez essayer : Multithreading avec Curl et PHP
Ce n’est pas l’astuce SEO Black Hat de la mort qui tue, mais je suis sûr que vous trouverez des applications qui vous seront utiles ![]()
Bon code.
Commentaires (12)
Catégorie: Scripts PHP
- Ajouter cet article à :
- Del.icio.us -
- Digg
Commentaire par Screu (1 commentaire)
Jeudi, 2 septembre , 2010 à 14:03
Et faire avec ça c’est pas possible :
http://www.reflectiv.net/blog/multi-threading-en-php5/
??
Commentaire par Maxime (1 commentaire)
Jeudi, 2 septembre , 2010 à 14:24
@Screu Si bien sûr, même si à mon sens la compréhension du code est plus délicate. Attention tout de même, PCNTL ne fonctionne que sous Unix. Le script Python de cet article peut tourner sur à peu prêt toutes les plateformes.
Commentaire par Jérôme (1 commentaire)
Jeudi, 2 septembre , 2010 à 15:02
Effectivement, pcntl est fait pour ça, et l’avantage du script python est vraiment la portabilité.
Commentaire par Maxime G. (1 commentaire)
Jeudi, 2 septembre , 2010 à 15:22
Ou sinon, un script bash qui lance les scripts avec la commande détachante « & »
Remplacer 4 par le nombre de core ou plus si vous avez de l’accès réseau (ce qui est un peu bloquant).
Ça tourne en parallèle, et c’est natif.
Par contre faut gérer la concurrence (pour pas qu’il fasse 4 fois la même chose)
#!/bin/bash
cd "$(dirname "$0")"
cmd='php update-feed.php'
for i in $(seq 1 4)
do
(eval $cmd) &
sleep 1 #optionnel
done
Commentaire par Olivier (12 commentaires)
Jeudi, 2 septembre , 2010 à 16:17
Salut Maxime,
Merci pour ton partage.
Cependant je crois que tu te compliques un peu la vie
. Il n’y a pas besoin de faire du multi-thread pour le cas de figure que tu as exposé : le multi requête via Curl en PHP est suffisant (cf http://php.net/manual/en/function.curl-multi-exec.php)
Commentaire par beunwa (1 commentaire)
Vendredi, 3 septembre , 2010 à 9:21
Excellent, une raison de plus de me mettre à python ! Merci
Commentaire par Ths
Lundi, 6 septembre , 2010 à 14:35
Pour ceux qui ne peuvent pas installer Python, et qui n’ont pas de dual core:
http://www.onlineaspect.com/2009/01/26/how-to-use-curl_multi-without-blocking/
Commentaire par BlackMelvyn (4 commentaires)
Jeudi, 9 septembre , 2010 à 9:57
Et moi qui vient d’installer Python sur mon mac, voilà tout de suite de quoi me motiver
Pour le multi-threading en PHP, j’ai un joli snippet qu’il faut que je te montre, on en discute bientôt
Merci pour le script en tout cas
Commentaire par salon dejardin (3 commentaires)
Samedi, 11 septembre , 2010 à 10:42
Ca fait longtemps que je veux prendre le temps de me mettre à Python, et bien voilà l’occasion rêvé !
Bien que le niveau est peut-être un peu élevé pour une première… ^^
En tous cas merci, je vais étudier ca de prêt !
Commentaire par skar
Dimanche, 17 octobre , 2010 à 0:26
Juste une question, peut on m’expliquer le but de la « temporisation » entre 2 parsings ?
Qu’entends tu par « La tempo pour passer sous les radars » ?
Moi je « curl » à la brutale et je me porte bien… Si tu pouvais m’expliquer le pourquoi du comment
merci.
Commentaire par lolo
Jeudi, 11 novembre , 2010 à 2:29
« Ce n’est pas l’astuce SEO Black Hat de la mort qui tue » => détrompe toi, ça va m’être grandement utile
))
MERCI !
Commentaire par Giloux (1 commentaire)
Mercredi, 24 novembre , 2010 à 11:04
Salut,
Et dire que je me plaignais de ne pas trouver de code en python pour la seo !!
Tu as raison, le multithreading est très puissant pour gagner beaucoup de temps quand on effectue des tâches où il y a beaucoup d’attente (comme la récupération d’url).
Fais attention tout de même à ne pas lancer trop de threads en même temps, ça pourrait poser un pb de ressources sur ta machine. Le mieux est d’utiliser un pool de threads qui dépilent tous une liste de tâches; tu peux ainsi maîtriser la charge. La classe python qui a tout ce qu’il faut pour faire ça est la Queue.
Si tu veux un exemple d’utilisation tu peux aller voir ici (je l’ai codé avec mes petits doigts
): http://python-seo.blooh.net/2010/11/16/thread-pool-en-python/















