J'ai trouvé ce package PECL appelé threads , mais il n'y a pas encore de version. Et rien ne se passe sur le site PHP.
J'ai trouvé ce package PECL appelé threads , mais il n'y a pas encore de version. Et rien ne se passe sur le site PHP.
Réponses:
Il n'y a rien de disponible que je sache. La meilleure chose à faire serait simplement qu'un script en exécute un autre via CLI, mais c'est un peu rudimentaire. En fonction de ce que vous essayez de faire et de sa complexité, cela peut être une option ou non.
Depuis le manuel PHP de l' extension pthreads :
pthreads est une API orientée objet qui permet le multi-threading utilisateur en PHP. Il comprend tous les outils dont vous avez besoin pour créer des applications multithreads ciblées sur le Web ou la console. Les applications PHP peuvent créer, lire, écrire, exécuter et se synchroniser avec des threads, des ouvriers et des empilables.
Aussi incroyable que cela puisse paraître, c'est tout à fait vrai. Aujourd'hui, PHP peut multi-thread pour ceux qui souhaitent l'essayer.
La première version de PHP4, le 22 mai 2000, PHP a été livrée avec une architecture thread-safe - un moyen d'exécuter plusieurs instances de son interpréteur dans des threads séparés dans des environnements SAPI (Server API) multi-threads. Au cours des 13 dernières années, la conception de cette architecture a été maintenue et avancée: depuis lors, elle est utilisée en production sur les plus grands sites Web du monde.
Threading dans le domaine des utilisateurs n'a jamais été une préoccupation pour l'équipe PHP, et il le reste aujourd'hui. Vous devez comprendre que dans le monde où PHP fait ses affaires, il existe déjà une méthode définie de mise à l'échelle - ajouter du matériel. Au fil des années, PHP a existé, le matériel est devenu moins cher et moins cher, ce qui est devenu de moins en moins une préoccupation pour l'équipe PHP. Alors qu'il devenait moins cher, il est également devenu beaucoup plus puissant; aujourd'hui, nos téléphones mobiles et tablettes ont des architectures double et quad core et beaucoup de RAM pour l'accompagner, nos ordinateurs de bureau et serveurs ont généralement 8 ou 16 cœurs, 16 et 32 gigaoctets de RAM, bien que nous ne puissions pas toujours en avoir deux dans le budget et avoir deux ordinateurs de bureau est rarement utile pour la plupart d'entre nous.
De plus, PHP a été écrit pour le non-programmeur, c'est la langue maternelle de nombreux amateurs. La raison pour laquelle PHP est si facilement adopté est qu'il s'agit d'un langage facile à apprendre et à écrire. La raison pour laquelle PHP est si fiable aujourd'hui est à cause de la grande quantité de travail qui va dans sa conception, et de chaque décision prise par le groupe PHP. C'est sa fiabilité et sa grandeur qui le maintiennent sous les projecteurs, après toutes ces années; où ses rivaux sont tombés sous la pression du temps ou de la pression.
La programmation multi-thread n'est pas facile pour la plupart, même avec l'API la plus cohérente et la plus fiable, il y a différentes choses à penser et de nombreuses idées fausses. Le groupe PHP ne souhaite pas que le multi-threading des utilisateurs soit une fonctionnalité essentielle, il n'a jamais reçu une attention particulière - et à juste titre. PHP ne doit pas être complexe, pour tout le monde.
Tout bien considéré, il y a encore des avantages à avoir à permettre à PHP d'utiliser ses fonctionnalités prêtes pour la production et testées pour permettre de tirer le meilleur parti de ce que nous avons, lorsque l'ajout de plus n'est pas toujours une option, et pour beaucoup des tâches n'est jamais vraiment nécessaire.
pthreads réalise, pour ceux qui souhaitent l'explorer, une API qui permet à un utilisateur de multi-thread des applications PHP. Son API est un travail en cours et a désigné un niveau bêta de stabilité et d'exhaustivité.
Il est de notoriété publique que certaines des bibliothèques utilisées par PHP ne sont pas sûres pour les threads, il devrait être clair pour le programmeur que pthreads ne peut pas changer cela et n'essaye pas d'essayer. Cependant, toute bibliothèque thread-safe est utilisable, comme dans toute autre configuration thread-safe de l'interpréteur.
pthreads utilise des threads Posix (même sous Windows), ce que le programmeur crée sont de vrais threads d'exécution, mais pour que ces threads soient utiles, ils doivent être conscients de PHP - capable d'exécuter du code utilisateur, de partager des variables et de permettre un moyen de communication utile (synchronisation). Ainsi, chaque thread est créé avec une instance de l'interpréteur, mais de par sa conception, son interpréteur est isolé de toutes les autres instances de l'interpréteur - tout comme les environnements d'API serveur multi-thread. pthreads tente de combler le fossé d'une manière saine et sûre. Beaucoup des préoccupations du programmeur de threads en C ne sont tout simplement pas là pour le programmeur de pthreads, de par leur conception, pthreads est copie en lecture et copie en écriture (la RAM est bon marché), donc aucune instance ne manipule jamais les mêmes données physiques , mais ils peuvent tous deux affecter les données d'un autre thread.
Pourquoi copier en lecture et copier en écriture:
public function run() {
...
(1) $this->data = $data;
...
(2) $this->other = someOperation($this->data);
...
}
(3) echo preg_match($pattern, $replace, $thread->data);
(1) Lorsqu'un verrou de lecture et d'écriture est maintenu sur le magasin de données d'objets pthreads, les données sont copiées de leur emplacement d'origine en mémoire vers le magasin d'objets. pthreads n'ajuste pas le refcount de la variable, Zend est capable de libérer les données d'origine s'il n'y a pas d'autres références à celles-ci.
(2) L'argument de someOperation fait référence au magasin d'objets, les données d'origine stockées, dont elle-même une copie du résultat de (1), sont copiées à nouveau pour le moteur dans un conteneur zval, tandis que cela se produit un verrou de lecture est maintenu sur le magasin d'objets, le verrou est libéré et le moteur peut exécuter la fonction. Lorsque le zval est créé, il a un refcount de 0, ce qui permet au moteur de libérer la copie à la fin de l'opération, car aucune autre référence n'existe.
(3) Le dernier argument de preg_match fait référence au magasin de données, un verrou de lecture est obtenu, l'ensemble de données de (1) est copié dans un zval, toujours avec un refcount de 0. Le verrou est libéré, l'appel à preg_match fonctionne sur une copie des données, qui est elle-même une copie des données originales.
Choses à savoir:
La table de hachage du magasin d'objets où les données sont stockées, thread-safe, est
basée sur la TsHashTable livrée avec PHP, par Zend.
Le magasin d'objets a un verrou de lecture et d'écriture, un verrou d'accès supplémentaire est fourni pour la TsHashTable de sorte que si cela nécessite (et c'est le cas, var_dump / print_r, un accès direct aux propriétés comme le moteur PHP veut les référencer) les pthreads peuvent manipuler la TsHashTable en dehors de l'API définie.
Les verrous ne sont maintenus que pendant les opérations de copie, lorsque les copies ont été faites, les verrous sont libérés, dans un ordre raisonnable.
Ça signifie:
Lorsqu'une écriture se produit, non seulement un verrou de lecture et d'écriture est maintenu, mais un verrou d'accès supplémentaire. La table elle-même est verrouillée, il n'y a aucun moyen possible qu'un autre contexte puisse la verrouiller, la lire, l'écrire ou l'affecter.
Lorsqu'une lecture se produit, non seulement le verrou de lecture est maintenu, mais également le verrou d'accès supplémentaire, la table est à nouveau verrouillée.
Deux contextes ne peuvent accéder physiquement ni simultanément aux mêmes données à partir du magasin d'objets, mais les écritures effectuées dans n'importe quel contexte avec une référence affecteront les données lues dans n'importe quel contexte avec une référence.
Il s'agit d'une architecture sans partage et la seule façon d'exister est de coexister. Ceux qui sont un peu avertis verront cela, il y a beaucoup de copies en cours ici, et ils se demanderont si c'est une bonne chose. Beaucoup de copies se font dans un environnement d'exécution dynamique, c'est la dynamique d'un langage dynamique. pthreads est implémenté au niveau de l'objet, car un bon contrôle peut être obtenu sur un objet, mais les méthodes - le code exécuté par le programmeur - ont un autre contexte, sans verrouillage ni copie - la portée de la méthode locale. La portée de l'objet dans le cas d'un objet pthreads doit être traitée comme un moyen de partager des données entre des contextes, c'est son but. Dans cet esprit, vous pouvez adopter des techniques pour éviter de verrouiller le magasin d'objets sauf si cela est nécessaire,
La plupart des bibliothèques et extensions disponibles pour PHP sont des wrappers légers autour de tiers, les fonctionnalités de base de PHP sont dans une certaine mesure la même chose. pthreads n'est pas une mince enveloppe autour de Posix Threads; c'est une API de threading basée sur Posix Threads. Il ne sert à rien d'implémenter des Threads en PHP que ses utilisateurs ne comprennent pas ou ne peuvent pas utiliser. Il n'y a aucune raison pour qu'une personne qui ne sait pas ce qu'est ou ce qu'est un mutex ne puisse pas profiter de tout ce qu'elle possède, à la fois en termes de compétences et de ressources. Un objet fonctionne comme un objet, mais partout où deux contextes se heurteraient autrement, pthreads offre stabilité et sécurité.
Quiconque a travaillé en java verra les similitudes entre un objet pthreads et le threading en java, ces mêmes personnes auront sans doute vu une erreur appelée ConcurrentModificationException - car cela sonne une erreur générée par le runtime java si deux threads écrivent les mêmes données physiques simultanément. Je comprends pourquoi cela existe, mais cela me déconcerte qu'avec des ressources aussi bon marché soient-elles, couplées au fait que le moteur d'exécution est capable de détecter la concurrence au moment exact et unique où la sécurité pourrait être assurée pour l'utilisateur, qu'il choisit de lancer une erreur potentiellement fatale lors de l'exécution plutôt que de gérer l'exécution et l'accès aux données.
Aucune erreur de ce genre ne sera émise par pthreads, l'API est écrite pour rendre le threading aussi stable et compatible que possible, je crois.
Le multi-threading n'est pas comme l'utilisation d'une nouvelle base de données, une attention particulière doit être portée à chaque mot du manuel et aux exemples livrés avec pthreads.
Enfin, à partir du manuel PHP:
pthreads était, et est, une expérience avec d'assez bons résultats. Chacune de ses limitations ou fonctionnalités peut changer à tout moment; c'est la nature de l'expérimentation. Ses limitations - souvent imposées par l'implémentation - existent pour une bonne raison; le but de pthreads est de fournir une solution utilisable au multitâche en PHP à tous les niveaux. Dans l'environnement dans lequel pthreads s'exécute, certaines restrictions et limitations sont nécessaires afin de fournir un environnement stable.
Voici un exemple de ce que Wilco a suggéré:
$cmd = 'nohup nice -n 10 /usr/bin/php -c /path/to/php.ini -f /path/to/php/file.php action=generate var1_id=23 var2_id=35 gen_id=535 > /path/to/log/file.log & echo $!';
$pid = shell_exec($cmd);
Fondamentalement, cela exécute le script PHP sur la ligne de commande, mais renvoie immédiatement le PID, puis s'exécute en arrière-plan. (L'echo $! Garantit que rien d'autre n'est retourné que le PID.) Cela permet à votre script PHP de continuer ou de se fermer si vous le souhaitez. Lorsque j'ai utilisé cela, j'ai redirigé l'utilisateur vers une autre page, où toutes les 5 à 60 secondes, un appel AJAX est effectué pour vérifier si le rapport est toujours en cours d'exécution. (J'ai une table pour stocker le gen_id et l'utilisateur auquel il est lié.) Le script de vérification exécute ce qui suit:
exec('ps ' . $pid , $processState);
if (count($processState) < 2) {
// less than 2 rows in the ps, therefore report is complete
}
Il y a un court article sur cette technique ici: http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/
En bref: oui, il y a du multithreading en php mais vous devriez plutôt utiliser le multiprocessing.
Il y a toujours un peu de confusion sur la distinction des threads et des processus, je vais donc les décrire brièvement:
Vous pouvez réaliser un calcul parallèle en créant de nouveaux processus (qui contiennent également un nouveau thread) avec php. Si vos threads n'ont pas besoin de beaucoup de communication ou de synchronisation, c'est votre choix, car les processus sont isolés et ne peuvent pas interférer avec le travail de l'autre. Même si l'un tombe en panne, cela ne concerne pas les autres. Si vous avez besoin de beaucoup de communication, vous devriez continuer à lire "multithreading" ou - malheureusement - envisager d'utiliser un autre langage de programmation, car la communication et la synchronisation inter-processus introduisent beaucoup de teint.
En php, vous avez deux façons de créer un nouveau processus:
laissez le système d'exploitation le faire pour vous : vous pouvez dire à votre système d'exploitation de créer un nouveau processus et d'exécuter un nouveau (ou le même) script php dedans.
pour Linux, vous pouvez utiliser ce qui suit ou considérer la réponse de Darryl Hein :
$cmd = 'nice php script.php 2>&1 & echo $!';
pclose(popen($cmd, 'r'));
pour Windows, vous pouvez utiliser ceci:
$cmd = 'start "processname" /MIN /belownormal cmd /c "script.php 2>&1"';
pclose(popen($cmd, 'r'));
faites-le vous-même avec un fork : php offre également la possibilité d'utiliser forking via la fonction pcntl_fork () . Un bon tutoriel sur la façon de faire cela peut être trouvé ici mais je recommande fortement de ne pas l'utiliser, car fork est un crime contre l'humanité et surtout contre oop.
Avec le multithreading, tous vos threads partagent leurs ressources afin que vous puissiez facilement communiquer entre eux et les synchroniser sans trop de surcharge. De l'autre côté, vous devez savoir ce que vous faites, car les conditions de course et les blocages sont faciles à produire mais très difficiles à déboguer.
Le PHP standard ne fournit pas de multithreading mais il existe une extension (expérimentale) qui le fait réellement - pthreads . Sa documentation API l'a même intégrée à php.net . Avec lui, vous pouvez faire des choses comme vous le pouvez dans de vrais langages de programmation :-) comme ceci:
class MyThread extends Thread {
public function run(){
//do something time consuming
}
}
$t = new MyThread();
if($t->start()){
while($t->isRunning()){
echo ".";
usleep(100);
}
$t->join();
}
Pour Linux, il y a un guide d'installation ici chez stackoverflow.
Pour Windows, il y en a un maintenant:
Editez [phpDirectory] /php.ini et insérez la ligne suivante
extension=php_pthreads.dll
Testez-le avec le script ci-dessus avec un peu de sommeil ou quelque chose juste là où se trouve le commentaire.
Et maintenant le gros MAIS : bien que cela fonctionne vraiment, php n'était pas à l'origine fait pour le multithreading. Il existe une version thread-safe de php et à partir de la v5.4, elle semble être presque sans bogue, mais l'utilisation de php dans un environnement multithread est toujours déconseillée dans le manuel php (mais peut-être qu'ils n'ont tout simplement pas mis à jour leur manuel sur ceci, encore). Un problème beaucoup plus important pourrait être que de nombreuses extensions courantes ne sont pas thread-safe . Vous pourriez donc avoir des threads avec cette extension php, mais les fonctions dont vous dépendez ne sont toujours pas sûres pour les threads, vous rencontrerez donc probablement des conditions de concurrence, des blocages, etc. dans un code que vous n'avez pas écrit vous-même ...
Vous pouvez utiliser pcntl_fork () pour réaliser quelque chose de similaire aux threads. Techniquement, ce sont des processus séparés, donc la communication entre les deux n'est pas aussi simple avec les threads, et je pense que cela ne fonctionnera pas si PHP est appelé par apache.
Si quelqu'un s'en soucie, j'ai relancé php_threading (pas le même que les threads, mais similaire) et je l'ai en fait au point où cela fonctionne (un peu) bien!
pcntl_fork()
est ce que vous recherchez, mais son processus ne tourne pas. vous aurez donc le problème de l'échange de données. pour les résoudre, vous pouvez utiliser les fonctions de sémaphore phps ( http://www.php.net/manual/de/ref.sem.php ) les files de messages peuvent être un peu plus faciles pour le début que les segments de mémoire partagée.
Quoi qu'il en soit, une stratégie que j'utilise dans un cadre Web que je développe et qui charge des blocs gourmands en ressources d'une page Web (probablement avec des demandes externes) en parallèle: je fais une file d'attente pour savoir quelles données j'attends, puis je fourche hors des travaux pour chaque processus. une fois terminé, ils stockent leurs données dans le cache apc sous une clé unique à laquelle le processus parent peut accéder. une fois que toutes les données sont là, elles continuent. J'utilise simple usleep()
to wait car la communication inter-processus n'est pas possible dans Apache (les enfants perdront la connexion avec leurs parents et deviendront des zombies ...). donc cela m'amène à la dernière chose: il est important de tuer chaque enfant! il y a aussi des classes qui bifurquent les processus mais conservent des données, je ne les ai pas examinées mais zend framework en a une, et elles codent généralement lentement mais de manière fiable. Vous pouvez le trouver ici:
http://zendframework.com/manual/1.9/en/zendx.console.process.unix.overview.html
je pense qu'ils utilisent des segments shm! Enfin, il y a une erreur sur ce site Web zend, une erreur mineure dans l'exemple.
while ($process1->isRunning() && $process2->isRunning()) {
sleep(1);
}
should of course be:
while ($process1->isRunning() || $process2->isRunning()) {
sleep(1);
}
Il existe une extension Threading en cours de développement, basée sur PThreads, qui semble très prometteuse sur https://github.com/krakjoe/pthreads
Juste une mise à jour, il semble que les gars de PHP travaillent sur le support des threads et sont disponibles maintenant.
Voici le lien vers celui-ci: http://php.net/manual/en/book.pthreads.php
J'ai une classe de threading PHP qui fonctionne parfaitement dans un environnement de production depuis plus de deux ans maintenant.
EDIT: Ceci est maintenant disponible en tant que bibliothèque de compositeur et dans le cadre de mon framework MVC, Hazaar MVC.
Je sais que c'est une question très ancienne, mais vous pouvez consulter http://phpthreadlib.sourceforge.net/
Communication bidirectionnelle, prise en charge de Win32 et aucune extension requise.
Avez-vous déjà entendu parler appserver
de techdivision?
Il est écrit en php et fonctionne comme un serveur d'applications gérant les multithreads pour les applications php à fort trafic. Est toujours en version bêta mais très prometteur.
Il y a la fonction plutôt obscure, et bientôt obsolète, appelée ticks . La seule chose pour laquelle je l'ai jamais utilisé est de permettre à un script de capturer SIGKILL (Ctrl + C) et de se fermer gracieusement.
pcntl_fork()
) fonctionnera s'il est appelé depuis Apache?