2017-09-21 12 views
1

cette question a à voir avec la théorie comme avec la programmation de la vie réelle je l'ai d'abord demandé (cs.stackexchange.com) parce que c'est la théorie la plus et j'ai eu l'instruction de demander ici (https://cs.stackexchange.com/questions/81472/question-about-implementing-websockets-theory-and-the-reality-in-php). J'expérimente avec des sockets Web et PHP depuis de nombreuses années (une partie de ce code est déjà en production), d'abord j'ai créé à partir de zéro un serveur WebSocket (WS) avec IO non bloquant et tout a bien fonctionné, sauf dans la vraie vie les autres méthodes requises par l'application ne peuvent pas être non bloquantes (par exemple, connexion à une base de données et une requête). Ensuite, j'ai introduit la programmation asynchrone, ce qui signifie que le serveur WS a initié diverses requêtes PHP au serveur et qu'il vérifie chaque boucle si ces requêtes ont fini les résultats afin de les envoyer au client. Cela a bien fonctionné pour quelques utilisateurs côté client connectés à ce serveur WS, le nombre avait à voir avec ce que l'opération était mais il ne serait pas plus de 30 ou 50. Parce que si vous utilisez un seul thread et vous avez beaucoup de simultanée demandes que vous devez vérifier chacun d'eux séquentielle s'il y a un résultat fini. L'étape suivante consistait à analyser le code des approches populaires prétendant pouvoir stocker et traiter de nombreux clients (certains disent 10 000) en même temps. Peut-être qu'ils savaient quelque chose que je n'ai pas (Ma question n'est pas s'ils mentent, la question est de savoir s'il y a quelque chose que je suis absent (ou peut-être que je me trompe) ici). Les résultats étaient frustrants. La plupart d'entre eux n'utilisent pas async par défaut pour vous conseiller de ne pas utiliser de méthodes de blocage (ce qui est vraiment impossible dans la vraie vie), mais même si vous leur mettez des modules pour les async le même problème. La question n'est pas quelle est la solution, car j'ai implémenté PHP pthreads et je pouvais le faire fonctionner, mais sans réel bénéfice (par exemple partager des objets, il fallait sérialiser tout désérialiser), j'écris des extensions PHP C++ années maintenant, donc je travaille dans une extension PHP qui le fera efficacement.Implémentation WebSockets, la théorie et la réalité en PHP

La question est ici, ai-je oublié quelque chose? Comment peuvent-ils prétendre que le bidon peut traiter une grande quantité de demande simultanément alors même avec la programmation asynchrone ils doivent vérifier chaque demande dans la boucle qui a fini?

Merci d'avance pour toute nouvelle connaissance ou direction de recherche que votre réponse pourrait me conduire.

+0

Ne pas Je veux dire quelque chose de stupide mais j'ai toujours eu l'impression que les discussions ** sont ** la solution. Vous avez juste besoin de trouver une manière décente de partager la mémoire entre les threads (pas très expérimenté avec pthread mais les bibliothèques de threads C n'ont jamais eu de problème avec le passage des objets en supposant que vous saviez détecter les sections critiques et ajouter des verrous). – apokryfos

+0

apokryfos c'est ce que je fais maintenant, je crée ceci comme une extension PHP en C++ (nous ne partageons pas d'objets car cela signifierait un verrouillage/déverrouillage du côté PHP, ce que nous faisons, c'est que plusieurs objets sérialisés sont partagés à cette requête et après la requête on compare cet objet avec le principal de ce contexte). Le noyau de PHP n'est pas une aventure de programmation joyeuse et si je manque juste quelque chose ici et les réclamations employant juste async et un serveur d'E/S non bloquant de WS ont n'importe quelle signification (ou vérité) que je voudrais le savoir. C'est ce que je demande, ai-je raison ou est-ce que quelque chose me manque? – jkon

Répondre

0

Oui, il y a des projets qui rendent cela possible avec PHP. Un tel projet est Amp avec son serveur HTTP et WebSocket Aerys. Oui, vous ne pouvez pas simplement appeler des fonctions de blocage dans le même thread. Oui, pthreads n'aidera pas, c'est presque comme si vous exécutiez un autre processus PHP, parce que tout ce qui est en PHP n'est rien partagé. Mais comment ça marche alors?

Utilisez des implémentations non bloquantes si possible. Il existe des bibliothèques qui fonctionnent avec des E/S non bloquantes pour l'accès à la base de données, telles que amphp/mysql.

S'il n'y a pas une telle bibliothèque, demandez si quelque chose comme ça peut être implémenté si vous ne voulez pas/ne pouvez pas l'implémenter vous-même.

Une autre possibilité consiste à utiliser des bibliothèques telles que amphp/parallel qui utilisent des travailleurs persistants pour bloquer les tâches. La création d'un autre worker pour chaque tâche de blocage serait terriblement inefficace, de sorte que la bibliothèque facilite l'utilisation des pools de travailleurs et permet de garder ces travailleurs en vie pour plusieurs tâches chacun.

Une telle bibliothèque qui utilise amphp/parallel est amphp/file, qui utilise ces travailleurs pour l'accès au système de fichiers non-blocage lorsque aucune extension comme uv ou eio sont disponibles, peut-être que vous voulez jeter un oeil à son ParallelDriver.

Le nombre de connexions que vous pourrez gérer simultanément dépend beaucoup de votre matériel et de ce que vous faites avec ces connexions. Si vous diffusez constamment des données sur chaque client, vous pourrez conserver beaucoup moins de connexions ouvertes que dans une situation où la plupart des connexions sont inactives et n'envoie/reçoit quelque chose que dans une petite partie de l'heure connectée.

Si vous voulez traiter plus de ~ 1000 clients, vous avez probablement besoin d'une extension ou recompiler PHP en raison de la FD_MAXSIZE pour stream_select, qui est compilé et limites stream_select aux descripteurs de fichiers inférieurs à 1024.

+0

Kelunik merci pour votre réponse et pour votre contribution à la communauté PHP. Je n'ai pas entendu parler d'ampli et certainement je vais l'essayer. J'ai quelques questions cependant. Vous n'avez pas besoin de vérifier pour chaque "événement" qu'il a terminé pour continuer? Est-il correct que pendant que vous faites cette vérification (et l'action nécessaire lorsque l'événement se termine) vous ne pouvez pas procéder dans ce fil principal? Si oui, combien d'événements simultanés (approximativement) pouvez-vous exécuter sans affecter de manière significative votre serveur WS? (J'ai vu la méthode tick dans Amp \ Loop \ Driver mais je n'avais pas encore le temps de la lire à fond et de l'analyser) – jkon

+0

Vérifier pour chaque événement s'il était fini serait assez inefficace. Pour les temporisateurs, il y a une file d'attente avec les éléments triés par "expiration", donc le prochain temporisateur à exécuter est toujours en tête de file. Le multiplexage d'E/S se fait avec 'stream_select' ou des appels système similaires, donc c'est dans le noyau. IIRC 'stream_select' se dégrade linéairement avec le nombre de descripteurs de fichiers qui lui sont transmis, mais d'autres options sont disponibles si vous avez vraiment besoin de beaucoup de clients pour garder les connexions ouvertes. Ces vérifications ne bloquent pas vraiment le thread principal à moins qu'il n'y ait rien à faire. – kelunik