web-dev-qa-db-fra.com

Traitement parallèle en PHP - Comment faites-vous?

J'essaie actuellement d'implémenter une file d'attente de travaux en php. La file d'attente sera ensuite traitée comme un travail par lots et devrait pouvoir traiter certains travaux en parallèle.

J'ai déjà fait quelques recherches et trouvé plusieurs façons de le mettre en œuvre, mais je ne connais pas vraiment leurs avantages et leurs inconvénients.

Par exemple. faire le traitement parallèle en appelant plusieurs fois un script via fsockopen comme expliqué ici:
Traitement parallèle facile en PHP

J'ai trouvé une autre façon d'utiliser le curl_multi les fonctions.
curl_multi_exec PHP docs

Mais je pense que ces 2 façons ajouteront à peu près des frais généraux pour créer un traitement par lots sur une file d'attente qui devrait principalement fonctionner en arrière-plan?

J'ai aussi lu sur pcntl_fork qui semble également être un moyen de résoudre le problème. Mais cela ressemble à ça peut devenir vraiment désordonné si vous ne savez pas vraiment ce que vous faites (comme moi en ce moment;)).

J'ai également jeté un coup d'œil à Gearman, mais là, je devrais également générer les threads de travail de manière dynamique selon les besoins et pas simplement en exécuter quelques-uns et laisser le serveur de tâches Gearman l'envoyer ensuite aux travailleurs libres. Surtout parce que les threads doivent être sortis proprement après l'exécution d'un travail, pour ne pas rencontrer d'éventuelles fuites de mémoire (le code peut ne pas être parfait dans ce problème).
Mise en route de Gearman

Donc ma question est, comment gérez-vous le traitement parallèle en PHP? Et pourquoi choisissez-vous votre méthode, quels avantages/inconvénients les différentes méthodes peuvent-elles avoir?

Merci pour toute contribution.

33
enricog

j'utilise exec(). C'est facile et propre. Vous devez essentiellement créer un gestionnaire de threads et des scripts de threads, qui feront ce dont vous avez besoin.

Je n'aime pas fsockopen() car cela ouvrira une connexion au serveur, qui se développera et pourrait atteindre la limite de connexion d'Apache

Je n'aime pas les fonctions curl pour la même raison

Je n'aime pas pnctl car il a besoin de l'extension pnctl disponible, et vous devez garder une trace des relations parents/enfants.

jamais joué avec gearman ...

16
Quamis

Eh bien, je suppose que nous avons 3 options:

A. Multi-thread:

PHP ne prend pas en charge le multithread en natif. Mais il y a une PHP (expérimentale) appelée pthreads ( https://github.com/krakjoe/pthreads ) qui vous permet de faire exactement cela.

B. Multi-processus:

Cela peut se faire de 3 manières:

  • Forking
  • Exécution de commandes
  • Piping

C. Traitement parallèle distribué:

Comment ça marche:

  1. L'application Client envoie des données (message AKA) "peut être formaté JSON" au moteur (moteur MQ) "peut être local ou externe un service Web"
  2. Le MQ Engine stocke les données "principalement dans la mémoire et éventuellement dans la base de données" dans une file d'attente (vous pouvez définir le nom de la file d'attente)
  3. L'application Client demande au moteur MQ de traiter les données (message) dans l'ordre (FIFO ou en fonction de la priorité) "vous pouvez également demander des données à une file d'attente spécifique".


Certains moteurs MQ:

  • ZeroMQ (bonne option, difficile à utiliser) un message orienté IPC Library, est un serveur de file d'attente de messages à Erlang, stocke les travaux en mémoire. Il s'agit d'une bibliothèque de sockets qui agit comme un cadre de concurrence. Plus rapide que TCP pour les produits en cluster et le supercalcul).
  • RabbitMQ (bonne option, facile à utiliser) auto-hébergé, Enterprise Message Queues, Pas vraiment une file d'attente de travail - mais plutôt une file d'attente de messages qui peut être utilisée comme une file d'attente de travail mais nécessite une sémantique supplémentaire.
  • Beanstalkd (meilleure option, facile à utiliser) (Laravel support intégré, construit par facebook, pour la file d'attente de travail) - a un outil "Beanstalkd console" qui est très beau
  • Gearman (problème: système de courtier centralisé pour le traitement distribué)
  • Apache ActiveMQ le courtier de messages open source le plus populaire en Java, (problème: beaucoup de bugs et de problèmes)
  • Amazon SQS (Laravel support intégré, hébergé - donc aucune administration n'est requise. Pas vraiment une file d'attente de travail nécessitera donc un travail supplémentaire pour gérer la sémantique telle que l'enterrement un travail)
  • IronMQ (Laravel support intégré, Written in Go, disponible à la fois en version cloud et sur site)
  • Redis (Laravel support intégré, pas si rapide que ce n'est pas conçu pour ça)
  • Sparrow (écrit en Ruby celui basé sur memcache)
  • Starling (écrit en Ruby celui basé sur memcache, construit sur Twitter)
  • Kestrel (juste un autre QM)
  • Kafka (écrit sur LinkedIn à Scala)
  • EagleMQ gestionnaire de files d'attente open source, hautes performances et léger (écrit en C)

Plus d'entre eux peuvent être trouvés ici: http://queues.io

8
Mahmoud Zalt

Si votre application doit fonctionner sous un environnement unix/linux, je vous suggère de choisir l'option forking. C'est essentiellement le jeu des enfants pour le faire fonctionner. Je l'ai utilisé pour un gestionnaire Cron et j'avais du code pour qu'il revienne à un chemin de code convivial Windows si la fourche n'était pas une option.

Les options consistant à exécuter plusieurs fois l'intégralité du script ajoutent, comme vous le dites, un peu de surcharge. Si votre script est petit, ce n'est peut-être pas un problème. Mais vous vous habituerez probablement à faire du traitement parallèle en PHP par la façon dont vous choisissez d'aller. Et la prochaine fois que vous avez un travail qui utilise 200 Mo de données, cela pourrait très bien être un problème. Donc, vous feriez mieux d'apprendre une manière avec laquelle vous pouvez vous en tenir.

J'ai aussi testé Gearman et je l'aime beaucoup. Il y a quelques choses à penser, mais dans l'ensemble, il offre un très bon moyen de distribuer des œuvres sur différents serveurs exécutant différentes applications écrites dans différentes langues. En plus de le configurer, de l'utiliser en réalité à partir de PHP, ou de tout autre langage d'ailleurs, c'est ... encore une fois ... le jeu des enfants.

Cela pourrait très bien être exagéré pour ce que vous devez faire. Mais cela vous ouvrira les yeux sur de nouvelles possibilités en ce qui concerne la gestion des données et des travaux, donc je vous recommande d'essayer Gearman pour ce seul fait.

3
inquam

J'utilise pnctl de PHP - c'est bon tant que vous savez ce que vous faites. Je comprends votre situation mais je ne pense pas que ce soit quelque chose de difficile à comprendre notre code, nous devons juste être un peu plus conscients que jamais lors de l'implémentation de la file d'attente JOB ou du processus parallèle.

Je pense que tant que vous le codez parfaitement et assurez-vous que le flux est parfait, vous devez garder à l'esprit le PROCESSUS PARALLÈLE lorsque vous l'implémentez.

Où vous pourriez faire des erreurs:

  1. Boucles - devraient pouvoir être gérées par les vars GLOBAL.
  2. Traitement d'un ensemble de transactions - encore une fois tant que vous définissez les ensembles appropriés, vous devriez pouvoir le faire.

Jetez un coup d'œil à cet exemple - https://github.com/rakesh-sankar/Tools/blob/master/PHP/fork-parallel-process.php .

J'espère que cela aide.

2
Rakesh Sankar

Je préfère exec () et gearman. exec () est facile et sans connexion et consomme moins de mémoire. Gearman devrait avoir besoin d'une connexion de prise et le travailleur devrait prendre de la mémoire. Mais gearman est plus flexible et plus rapide que exec (). Et le plus important est qu'il peut déployer le travailleur sur un autre serveur. Si le travail demande du temps et des ressources. J'utilise gearman dans mon projet actuel.

2
Magic

Voici un résumé de quelques options de traitement parallèle en PHP.

AMP

Checkout Amp - Accès simultané asynchrone simplifié - cela semble être le plus mature PHP bibliothèque que j'ai vue pour le traitement parallèle.

Classe de processus de Peec

Cette classe a été publiée dans les commentaires de la fonction exec () de PHP et fournit un véritable point de départ simple pour forger de nouveaux processus et en garder la trace.

Exemple:

// You may use status(), start(), and stop(). notice that start() method gets called automatically one time.
$process = new Process('ls -al');

// or if you got the pid, however here only the status() metod will work.
$process = new Process();
$process.setPid(my_pid);

// Then you can start/stop/check status of the job.
$process.stop();
$process.start();
if ($process.status()) {
    echo "The process is currently running";
} else {
    echo "The process is not running.";
}

Autres options comparées

Il y a aussi un excellent article Traitement asynchrone ou multitâche en PHP qui explique les avantages et les inconvénients de différentes approches:

Portier

Ensuite, il y a aussi ce tutoriel simple qui a été enveloppé dans une petite bibliothèque appelée Portier .

J'espère que ces liens fournissent un point de départ utile pour plus de recherches.

1
Simon East

La méthode décrite dans 'Traitement parallèle facile en PHP' est carrément effrayante - le principe est OK - mais l'implémentation ??? Comme vous l'avez déjà souligné, les curl_multi_ fns offrent une bien meilleure façon de mettre en œuvre cette approche.

Mais je pense que ces 2 façons ajouteront à peu près les frais généraux

Oui, vous n'avez probablement pas besoin d'une pile HTTP client et serveur pour transférer le travail - mais à moins que vous ne travailliez pour Google, votre temps de développement est beaucoup plus cher que vos coûts matériels - et il existe de nombreux outils pour gérer HTTP/analyser les performances - et il existe une norme définie couvrant des éléments tels que les notifications d'état et l'authentification.

Une grande partie de la façon dont vous implémentez la solution dépend du niveau d'intégrité transactionnelle dont vous avez besoin et si vous avez besoin d'un traitement dans l'ordre.

Parmi les approches que vous mentionnez, je vous recommande de vous concentrer sur la méthode de requête HTTP en utilisant curl_multi_. Mais si vous avez besoin d'un bon contrôle transactionnel/pour la livraison des commandes, vous devez certainement exécuter un démon de courtier entre la source des messages et les agents de traitement (il existe un serveur à thread unique bien écrit pouvant être utilisé comme cadre pour le courtier ici ). Notez que les agents de traitement doivent traiter un seul message à la fois.

Si vous avez besoin d'une solution hautement évolutive, jetez un œil à un système de mise en file d'attente de messages approprié tel que RabbitMQ .

HTH

C.

1
symcbean