Combien de demandes simultanées un processus Flask unique reçoit-il?

138

Je construis une application avec Flask, mais je ne sais pas grand-chose sur WSGI et sa base HTTP, Werkzeug. Lorsque je commence à servir une application Flask avec gunicorn et 4 processus de travail, cela signifie-t-il que je peux gérer 4 requêtes simultanées?

Je veux dire des demandes simultanées, et non des demandes par seconde ou quoi que ce soit d'autre.

Carson
la source

Réponses:

183

Lorsque vous exécutez le serveur de développement - ce que vous obtenez en exécutant app.run(), vous obtenez un seul processus synchrone, ce qui signifie qu'au plus 1 demande est traitée à la fois.

En plaçant Gunicorn devant lui dans sa configuration par défaut et en augmentant simplement le nombre de --workers, vous obtenez essentiellement un certain nombre de processus (gérés par Gunicorn) qui se comportent chacun comme le app.run()serveur de développement. 4 ouvriers == 4 requêtes simultanées. En effet, Gunicorn utilise son synctype de travailleur inclus par défaut.

Il est important de noter que Gunicorn comprend également des travailleurs asynchrones, à savoir eventletet gevent(et aussi tornado, mais il est préférable de l'utiliser avec le framework Tornado, semble-t-il). En spécifiant l'un de ces travailleurs asynchrones avec l' --worker-classindicateur, vous obtenez que Gunicorn gère un certain nombre de processus asynchrones, chacun gérant sa propre concurrence. Ces processus n'utilisent pas de threads, mais plutôt des coroutines. Fondamentalement, dans chaque processus, une seule chose peut se produire à la fois (1 thread), mais les objets peuvent être `` mis en pause '' lorsqu'ils attendent la fin des processus externes (pensez aux requêtes de base de données ou en attente d'E / S réseau).

Cela signifie que si vous utilisez l'un des nœuds de calcul asynchrones de Gunicorn, chaque collaborateur peut gérer bien plus qu'une seule requête à la fois. Le nombre de travailleurs qui convient le mieux dépend de la nature de votre application, de son environnement, du matériel sur lequel elle fonctionne, etc. Plus de détails peuvent être trouvés sur la page de conception de Gunicorn et des notes sur le fonctionnement de gevent sur sa page d'introduction.

Ryan Artecona
la source
4
Gunicorn supporte désormais les "vrais" threads depuis la version 19. Voir ceci et cela .
Filipe Correia
2
Comment savoir quelles ressources sont partagées (et comment) et lesquelles sont complètement séparées entre les threads / processus? Par exemple, comment gérer une situation où je souhaite partager une énorme structure de données entre plusieurs processus gérés par Gunicorn et utilisés dans les gestionnaires Flask?
Johann Petrak
Ce que vous demandez à @Johsm, c'est comme demander comment partager des données entre différents processus au sein du système d'exploitation. La réponse à cela peut répondre à votre question, vous devez utiliser le stockage externe car les processus ne partagent pas sa mémoire avec d'autres processus. Gunicorn est ici uniquement pour utiliser des architectures de processeur multiprocesseur mais ne gère pas ces problèmes.
adkl
Et Eve? Cela vaut-il aussi pour Eve?
Eswar
2
le serveur de développement de flask utilise des threads par défaut depuis la v1.0 ( github.com/pallets/flask/pull/2529 )
hychou
40

Il existe actuellement une solution bien plus simple que celles déjà proposées. Lors de l'exécution de votre application, il vous suffit de transmettre le threaded=Trueparamètre à l' app.run()appel, comme:

app.run(host="your.host", port=4321, threaded=True)

Une autre option selon ce que nous pouvons voir dans la documentation werkzeug , est d'utiliser le processesparamètre, qui reçoit un nombre> 1 indiquant le nombre maximum de processus simultanés à gérer:

  • threaded - le processus doit-il gérer chaque demande dans un thread distinct?
  • processus - si supérieur à 1, traiter chaque demande dans un nouveau processus jusqu'à ce nombre maximum de processus simultanés.

Quelque chose comme:

app.run(host="your.host", port=4321, processes=3) #up to 3 processes

Plus d'infos sur la run()méthode ici , et le billet de blog qui m'a amené à trouver la solution et les références API.


Remarque: dans la documentation Flask sur les run()méthodes, il est indiqué que son utilisation dans un environnement de production est déconseillée car ( citation ): "Bien que léger et facile à utiliser, le serveur intégré de Flask ne convient pas à la production car il ne s'adapte pas bien . "

Cependant, ils pointent vers leur page Options de déploiement pour les méthodes recommandées pour le faire lors de la mise en production.

DarkCygnus
la source
5
Merci pour l'info. Il est important de noter que le document pour run indique qu'il ne doit pas être utilisé dans un environnement de production en indiquant qu'il ne répond pas aux exigences de sécurité ou de performances.
Coffee_fan
1
@Coffee_fan vous avez raison. Même sur la dernière version 1.1.x, ils découragent cela et suggèrent plutôt de consulter leur page sur les options de déploiement lors de la mise en production. Y compris votre précieuse observation dans la réponse :)
DarkCygnus
33

Flask traitera une demande par thread en même temps. Si vous avez 2 processus avec 4 threads chacun, cela fait 8 requêtes simultanées.

Flask ne génère ni ne gère les threads ou les processus. C'est la responsabilité de la passerelle WSGI (par exemple, gunicorn).

jd.
la source
9

Non, vous pouvez certainement gérer plus que cela.

Il est important de se rappeler qu'au fond, en supposant que vous exécutez une machine à un seul cœur, le processeur n'exécute en réalité qu'une seule instruction * à la fois.

À savoir, le CPU ne peut exécuter qu'un ensemble d'instructions très limité, et il ne peut pas exécuter plus d'une instruction par tick d'horloge (de nombreuses instructions prennent même plus d'un tick).

Par conséquent, la plupart des concurrents dont nous parlons en informatique est la concurrence logicielle. En d'autres termes, il existe des couches d'implémentation logicielle qui nous extraient le processeur de niveau inférieur et nous font penser que nous exécutons du code simultanément.

Ces «choses» peuvent être des processus, qui sont des unités de code exécutées simultanément dans le sens où chaque processus pense qu'il s'exécute dans son propre monde avec sa propre mémoire non partagée.

Un autre exemple est celui des threads, qui sont des unités de code à l'intérieur des processus qui permettent également la concurrence.

La raison pour laquelle vos 4 processus de travail seront capables de gérer plus de 4 requêtes est qu'ils déclencheront des threads pour gérer de plus en plus de requêtes.

La limite de demande réelle dépend du serveur HTTP choisi, des E / S, du système d'exploitation, du matériel, de la connexion réseau, etc.

Bonne chance!

* les instructions sont les commandes de base que le CPU peut exécuter. exemples - ajouter deux nombres, passer d'une instruction à une autre

user1094786
la source
1
Est-ce que c'est le gunicorn qui génère les fils ou le flacon? Je n'ai trouvé aucune preuve étayant l'une ou l'autre possibilité.
jd.
1
Bien sûr, je comprends cela à propos des processus, mais la réponse dit que plus de threads sont générés au besoin. C'est ce dont j'aimerais avoir la confirmation.
jd.
4
"au fond, en supposant que vous exécutez une machine à un seul cœur, le CPU n'exécute en réalité qu'une seule instruction * à la fois" Ce n'est pas correct sur les machines modernes. La plupart des processeurs modernes sont en pipeline et superscalaires , où même un seul cœur possède plusieurs unités d'exécution et un décodeur d'instructions qui convertit le «code machine» vu du côté logiciel en micro-opérations matérielles réelles qui sont envoyées aux unités d'exécution individuelles.
Michael Geary
1
Pour clarifier, il y a longtemps, les processeurs exécutaient directement les instructions numériques dans un exécutable - le code machine. Chaque référence CPU avait un chronogramme d'instructions indiquant le nombre de cycles d'horloge que chaque instruction prenait, y compris les références mémoire. Vous pouvez donc simplement additionner les horaires pour savoir combien de temps un morceau de code prendrait. Les processeurs modernes ne sont pas du tout comme ça. Une exception intéressante est le BeagleBone qui a un processeur ARM superscalaire moderne et deux processeurs "PRU" à l'ancienne avec une synchronisation d'instruction fixe.
Michael Geary
1
Et pour clarifier cela , quand j'ai dit «moderne», je l'utilisais comme un raccourci pour des processeurs comme les puces ARM / Intel / AMD - pipelined, superscalaire, etc. Bien sûr, il existe également des processeurs modernes qui fonctionnent à l'ancienne avec une synchronisation fixe par instruction, comme les PRU BeagleBone que j'ai mentionnés et divers nouveaux microcontrôleurs. (Et maintenant revenons à Gunicorn!)
Michael Geary