Transcription
1. Introduction dans la programmation simultanée: Hé là et bienvenue. Mon nom est Max, fondateur du codage avec Max et point de contrôle des données. Et ce cours, nous allons passer par la programmation simultanée et parallèle en Python. Nous allons apprendre comment nous pouvons écrire des programmes de thread, comment nous pouvons écrire des programmes de multitraitement, ainsi que comment nous pouvons également écrire des applications asynchrones. Et nous allons passer à travers, et nous allons en fait construire un très grand programme threadé qui va lire données de Yahoo Finance pour obtenir un processus, puis téléchargé dans des bases de données. Ensuite, nous allons également écrire des programmes multitraitement afin que nous puissions nous assurer que nous
puissions tirer le meilleur parti de tous les cœurs CPU disponibles sur votre machine. Ensuite, nous allons également apprendre comment nous pouvons écrire des applications asynchrones, comment elles fonctionnent et à quoi vous pouvez les utiliser. Donc avec ça, j'espère te voir à l'intérieur.
2. Filtrage et multitraitement, Introduction Async: Hé, c'est Max et bienvenue. Dans ce module, nous allons en apprendre davantage sur la programmation simultanée. Avant d'entrer et d'écrire des programmes sympas, nous allons rapidement obtenir un aperçu et un aperçu de ce que nous allons couvrir ici afin que nous soyons tous prêts et comprenions généralement ce que nous allons faire. Donc, tout d'abord, le plan de cette leçon est d'abord que nous allons
juste avoir une brève introduction à la concurrence, juste en regardant quelques exemples et pourquoi c'est même cool et pourquoi nous pouvons vouloir l'utiliser. Et puis nous allons juste entrer dans quelques considérations sur des choses que nous devons garder
à l'esprit quand nous pensons à écrire des programmes simultanés. D' accord ? Donc, en général, quand nous écrivons des programmes, il est très probable que nous allons écrire des programmes séquentiels. Donc, une chose se passe après l'autre. Et la plupart du temps, nous sommes presque tout le temps jusqu'à présent il est écrit sur juste en utilisant un seul processeur. Cela signifie donc que nous ne faisons pas vraiment usage de toutes les ressources qui peuvent nous être mises à notre disposition. Jetons donc un coup d'oeil à cet exemple ici. Disons que notre machine a quatre cœurs et que nous exécutons un programme Python. Et fondamentalement, ce que nous faisons, c'est que nous calculons plusieurs métriques. Nous avons un fichier de source de données de quelque part, et nous voulions juste calculer quelques mesures différentes. Donc, la façon dont nous pouvons faire exécuter ce programme est d'abord nous calculons la première métrique, puis nous calculons la seconde, puis nous calculons la troisième, puis nous enregistrons tout dans un fichier. Et si on a quatre cœurs, ça veut dire que l'un de nos cœurs
est, va exécuter ce programme et les autres vont rester inactifs. Bien sûr, il y a d'autres considérations. Vous savez, si nous exécutons ça sur notre machine personnelle parce que d'autres applications
sont ouvertes, et cetera, et cetera. Mais si nous étions dans un environnement Cloud ou quelque chose et que nous avons réellement plus de ressources CPU disponibles, alors il se pourrait que nous ne tirions pas pleinement parti de toutes ces ressources disponibles. Donc pourrait être fait à la place est que nous pourrions avoir un programme qui calcule le jeu métrique. Et j'ai en quelque sorte changé les tailles ici pour montrer les différentes mesures peuvent prendre un temps différent pour calculer. Donc, vous avez la métrique A, qui va fonctionner sur le premier noyau. Et nous avons la métrique B, qui va être calculée en même temps sur le deuxième noyau. Et puis nous avons métrique SI, qui va être calculé en même temps sur le troisième noyau. Donc, comme ces mesures sont indépendantes les unes des autres, nous pouvons les calculer toutes en même temps. n'y a aucune raison que nous ayons besoin d'en attendre un pour finir. Et puis on fait la seconde, et ensuite on fera la troisième. Nous pourrions tous les calculer en même temps. Et puis une fois que chacun d'entre eux est terminé, nous pourrions aussi simplement les écrire dans un fichier. Et puis si nous le voulions, nous pourrions fusionner tous les fichiers ensemble ou quelque chose que nous pouvons aussi faire est que nous pouvons juste généralement remplacer l'enregistrement dans un fichier à la place par l'écriture dans une base de données. Donc, ce sera calculer une métrique et ensuite nous l'écrirons dans la base de données et ensuite, vous savez, cette partie est terminée. Donc, dans ce cas, ce que nous avons ici, c'est que nous avons un programme plus intensif de CPU. Il y a beaucoup de calculs en cours,
sur le goulot d'étranglement sont vraiment les calculs. Et donc dans ce cas, il est bon de faire usage de nos différents cœurs sont des ressources informatiques
différentes afin que nous puissions faire plus de calculs en même temps. Mais il y a aussi d'autres programmes que nous pouvons écrire où ce n'est pas tant de calcul, mais en fait beaucoup de temps passé par le programme est juste en attente de réponses réseau. Donc, par exemple, quelque chose que nous pourrions faire, c'est qu'on pourrait demander, je viens de quelque part. Cela pourrait être une API. Ça pourrait provenir d'un grattoir web, points, vous savez, sur le site Web. Mais de toute façon, on demande juste des données de quelque part. Et puis nous attendons que la réponse nous revienne. Et maintenant, nous avons les données disponibles. Et puis nous pouvons soit l'écrire dans un fichier, par exemple, ou nous pouvons l'écrire dans une base de données et en cours d'exécution dans une base est
en fait envoyer la demande pour dire, ok, s'il vous plaît écrire ceci et puis attendre la réponse du réseau. Oui. Ok, c'est écrit. Et puis si nous faisons cela pour plusieurs éléments de données et peut-être nous, nous demandons le premier élément de données et ensuite nous attendons la réponse à eux, nous l'écrivons et ensuite nous pouvons demander le deuxième élément de données, attendre la réponse, puis écrivez-le. Et l'écriture elle-même a encore une fois, envoyant la droite et en attendant qu'elle soit reconnue. Donc, dans ce cas, nous passons juste beaucoup de temps à attendre que les choses se passent. Nous passons beaucoup de temps à attendre des signaux d'accusé de réception. Oui. Voici vos données. Ok, c'est enfin disponible pour nous, comme comment être transféré sur le réseau. Ou Ici nous allons, oui, Les données ont maintenant été enregistrées dans la base de données. Donc, nous pouvons avoir, dans ce cas est que nous pouvons avoir plusieurs threads. Donc, nous avons toujours tout en cours d'exécution sur un seul processeur dans un seul cœur. Mais nous avons plusieurs programmes simultanés fonctionnant sur le même noyau. Donc nous pouvons avoir un fil principal, qui fondamentalement, si ça ne veut rien faire d'autre, il peut y avoir des choses qui se passent à l'avance, mais vraiment ça peut juste démarrer Oliver enfant, fils d'enfant. Et donc ce que le premier thread enfant fera, c'est qu'il va demander des données. Et pendant qu'il attend, le deuxième thread peut alors demander que c'est theta. Et puis quand les données entrent, alors il le peut, le premier thread peut dire, d'accord, maintenant j'ai mes données et je vais écrire ceci dans une base de données. Et puis il passe du temps à attendre à nouveau. Et alors qu'un thread attend la communication réseau, pour les accusés de réception réseau, l'autre thread peut faire son travail. Et donc vous pouvez voir ici. Nous avons deux threads qui fonctionnent simultanément, tout le genre de désactivation. Une demande les données et quand elles sont inactives, quand il attend juste que le réseau lui donne une réponse, l'autre thread peut être en cours d'exécution. Maintenant, il y a un autre exemple de choses qui peuvent arriver est que nous pouvons avoir beaucoup d'écriture dans des bases de données. Donc, une chose ici, bien
sûr comment nous pouvons faire est que nous pouvons utiliser des threads, encore une fois pour avoir plusieurs threads, chacun d'eux des droits sur une base de données. Et tandis que ce thread attend que la base de données donne un accusé de réception, l'autre thread peut initier son droit, et cetera. Maintenant, nous pouvons également utiliser un programme asynchrone où vous envoyez
essentiellement la droite et ensuite vous continuez avec le programme. Et chaque fois que vous obtenez l'accusé de réception, alors vous revenez à la partie terminée et passez au programme. Ainsi, votre programme n'est pas bloqué par ces temps de communication d'E/S réseau, mais vous écrivez simplement dans la base de données. Comme vous pouvez le voir sur le côté droit ici. Donc, nous écrivons dans la base de données, et pendant que nous attendons l'accusé de réception, nous lançons juste la deuxième droite à peut-être une autre base de données et ensuite nous pouvons même écrire peut-être dans une troisième base de données. Et donc tout cela se passe et en arrière-plan, vous savez, nous attendons d'entendre un accusé de réception de l'une des bases de données sur lesquelles nous avons écrit. Et chaque fois que nous recevons cette reconnaissance, nous pouvons poursuivre cette partie du programme. Et donc vraiment, cela nous aide à économiser beaucoup de temps que nous passerions autrement juste assis inactif à attendre que la communication réseau se produise. Maintenant, cela peut ne pas sembler une grosse affaire parce que, vous savez, les vitesses Internet peuvent être très rapides. Mais si vous faites beaucoup de communication
réseau comme si vous écriviez un tas de valeurs. Donc, si vous envoyez un tas de demandes, votre programme peut passer beaucoup de temps juste assis autour de l'inactivité, à attendre. Et donc avoir cette option d'utiliser des threads pour faire des choses pendant que nous attendons ou être capable de faire usage de plusieurs cœurs CPU si nous avons des opérations intensives de calcul, cela peut vraiment être un grand avantage pour nous et cela peut accélérer nos programmes dramatiquement. Maintenant, il y a bien sûr certains inconvénients et considérations que nous devons faire ici. Donc, la première chose que nous devons être conscients car Python a quelque chose connu comme un verrou d'interpréteur global, ce qui signifie fondamentalement que nous ne pouvons exécuter qu'un seul thread à la fois. Donc, vous pouvez voir ici si nous revenons à l'exemple, si nous regardons enfant un et thread enfant à thread enfant sauvage, on initie la demande pour les données. Le chapitre 2 est en fait inactif. Il ne lance pas sa propre demande. C' est seulement une montre tenue. cible 1 est inactive là où elle attend. Ce thread enfant T2, par
exemple, peut commencer à travailler. Donc, ils ne sont pas exactement simultanés, mais les threads sont en quelque sorte à tour de rôle. Et chaque fois que l'un est inactif, un
autre peut en quelque sorte sauter et prendre ce temps CPU. Et donc chaque fois
que quelque chose est inactif, c'est quand ils peuvent entrer. Donc, ce n'est pas une concurrence parfaite, mais bien sûr, nous obtenons toujours des accélérations spectaculaires parce que nous n'avons pas à passer tout ce temps à attendre et pendant que nous
attendons, nous ne faisons rien d'autre. Maintenant, il y a aussi un problème important. Nous devons penser que tout ne peut pas être thread safe. Donc, fondamentalement, les moyens thread-safe sont qu'il est correct que plusieurs threads traitent avec une certaine entité. Ou nos threads traitent les données de
manière à ne pas interférer avec d'autres menaces. Maintenant, une façon d'agir sur la sécurité des filets est d'utiliser le verrouillage. D' autres manières aussi simplement écrire des programmes thread-safe qui ne conduisent pas à des choses bizarres qui se produisent lorsque plusieurs threads essaient d'accéder, par
exemple, partager un morceau de données. Donc une de ces choses que nous pouvons obtenir si nous n'avons pas sécurité de
fil est quelque chose qu'on appelle une condition de course. Maintenant, c'est quelque chose que vous verrez ici dans les threads, mais peut également apparaître lorsque vous savez que vous apprenez à propos des bases de données. Mais fondamentalement, une condition de concurrence est lorsque deux programmes ou entités ou threads distincts, dans ce cas, essaient d'accéder et de modifier le même morceau de données ou même simplement d'utiliser les mêmes données. Donc, par exemple, disons que nous avons deux threads qui utilisent tous les deux une variable a. Et thread on lit la variable, puis la modifie et en même temps, ou peu de temps avant ou peu après thread pour lire également la variable et puis écrit à lui. Et il y a beaucoup de choses différentes qui peuvent arriver. Donc, par exemple, disons que chacun de ces threads incrémentant simplement la variable. Si nos deux threads les lisent presque simultanément
, ils verront tous les deux la même valeur. Et puis un thread, un genre de met son résultat n et l'incrémente juste par un. Thread 2 n'aura pas vu cette nouvelle valeur, mais aurait vu la valeur précédente. Et donc quand il l'incrémente d'un, il est seulement au total va être incrémenté d'un plutôt que de deux parce qu'ils le
lisent tous les deux à un moment similaire avant que l'un des autres ait terminé son opération. Et puis bien sûr, vous pouvez avoir d'autres variations de fondamentalement le même problème. Lorsque vous écrasez la variable, vous effectuez une opération en aval, par
exemple, en l'ajoutant ou en la multipliant, puis vous ne l'utilisez pas plus tard. Mais parce que les threads se produisent en quelque sorte simultanément, il est très difficile pour nous de savoir exactement. Il est fondamentalement impossible pour nous de savoir à quel thread va accéder au début, surtout en les connaissant sur une exécution différente du même programme. Donc, si nous réexécutons notre programme, cela peut conduire à des résultats imprévisibles car parfois un thread en fait le premier et parfois un autre thread peut y arriver en premier. Et parfois nous avons une condition de course. Parfois, nous ne le pouvons pas parce qu'ils sont aussi des facteurs externes en jeu. Et ainsi. Les conditions de course peuvent conduire à des résultats très imprévisibles. Et donc garder cela à l'esprit est très important que si vous avez partagé des données ou quelque chose comme
ça, vous devez toujours penser. sécurité des fils est le programme que j'écris peut interférer avec lui-même. Et si vous utilisez d'autres modules ou bibliothèques en Python, et que certains d'entre eux diront spécifiquement cette entité, par exemple, cette classe que vous utilisez est thread-safe ou cette classe n'est pas thread-safe. Et donc vous devez être conscient et prudent à
leur sujet parce que cela peut conduire à des bugs très, très bizarres, difficiles et compliqués et confus qui sont difficiles à reproduire et très difficiles à traquer. Donc, l'autre chose à considérer est d'abord de parler de fil. Plus précisément, les threads s'exécutent sur un seul cœur de CPU et ils partagent tous la même mémoire, c'est pourquoi nous avons ce problème de sécurité des threads et des conditions de course. Et il y a aussi une petite surcharge associée
à commutation de thread entre les différents threads, ainsi qu'à la gestion juste des threads à l'auto-création, arrachant les threads. Alors que pour le multitraitement et ce que nous avons est que nous avons différent le même programme fonctionnant sur différents cœurs de CPU, ou la même partie de ce programme fonctionnant sur différents cœurs de CPU. Et donc, en fait, dans ce cas, nous n'avons pas de mémoire partagée. Chaque processus a son propre interpréteur Python et son propre verrou d'interpréteur global. Donc, bien sûr, c'est génial parce que nous n'avons pas à avoir certains de ces problèmes que nous avons avec les menaces, par exemple. Mais il y a aussi plus de mémoire. Il y a aussi plus de frais généraux associés à cela. Donc, l'un d'entre eux est de réduire beaucoup de l'utilisation de la mémoire. Et il y a juste beaucoup plus de mémoire qui doit être utilisé pour créer et répliquer tous ces processus différents à travers les différents interprètes. Et juste à propos de la concurrence en général, c'est très cool et il peut être extrêmement utile en rapide. Nous voulons également nous assurer que les programmes que vous écrivez
en valent la peine d'écrire et d'une manière simultanée. Parce que l'écriture et le débogage de programmes simultanés peuvent devenir très complexes et il devient
parfois difficile de trouver des problèmes dans votre logique ou déboguer certains problèmes en raison de toute cette concurrence qui se passe. Donc oui, avec la concurrence, nous pouvons certainement obtenir des vitesses incroyables. Mais rappelez-vous aussi que tous les programmes ne doivent pas être simultanés. Et c'est très bien, vous savez, de continuer à écrire beaucoup de programmes séquentiels. Mais vous remarquerez que, Oh mon Dieu, je passe tellement de temps à attendre que tout ça ne marche pas. Je peux vraiment utiliser le multithreading ici, ou il n'y a aucune raison pour moi de calculer ces 80 métriques séquentiellement. Je vais juste utiliser le multitraitement et utiliser quatre, deux ou huit ou survoler nombreux cœurs que vous avez disponibles sur votre machine ou dans l'environnement Cloud et je vais juste accélérer le processus. Donc, ils sont certainement écrire des situations pour l'utiliser. Mais il y a aussi, vous savez, nous n'avons pas à écrire tous les programmes simultanément. Donc gardez cela à l'esprit parce que la concurrence ajoute la complexité à l'écriture et à la logique, ainsi qu'au débogage.
3. Filtrer en Python: Bon, alors allons de l'avant et écrire notre premier programme simultané. On va commencer par le filetage. Maintenant, je vais utiliser PyCharm pour cela, mais vous pouvez bien sûr, allez-y et sentez-vous libre d'utiliser quel que soit votre environnement de codage préféré. J' aime beaucoup utiliser PyCharm quand nous avons plusieurs fichiers, que je finirai en fait, vous savez, aller vers la dernière partie de pendant que nous progressons à travers le threading. Donc oui, tout à fait comme travailler avec un graphique à secteurs pour ça. Sinon, vous savez, si je fais un test rapide et un prototypage et que j'ai besoin de manipuler ou un
peu de vouloir regarder en arrière beaucoup de données qui
ont été créées tout au long d'un programme ou juste une sorte de jeu avec les choses. Pour cela, j'aime généralement utiliser une araignée ou Jupyter Notebooks. Mais en dehors de cela, j'aime beaucoup utiliser PyCharm. Encore une fois, c'est complètement à vous de décider. Donc, je viens de créer un dossier sur mon bureau ici où nous allons sauver tout notre travail. Je vais créer un nouveau fichier et appeler cette boîte. Je vais juste appeler ça ma principale, mais tu peux l'appeler comme tu veux tant qu'il a l'extension dot py. Et je vais faire quelque chose ici que vous verrez probablement beaucoup dans les programmes Python. Et nous allons commencer à définir une fonction principale. Et on va passer ici, ce qui nous laisse dire qu'on y reviendra plus tard. Donc pour l'instant, ça ne fera rien. Nous allons avoir la syntaxe ici. Si le trait de soulignement, le trait de
soulignement, le nom , le trait de soulignement est égal à. Et puis on a un soulignement. Soulignement, soulignement, soulignement, soulignement principal, soulignement. Et puis nous allons exécuter la fonction principale. Maintenant, fondamentalement, ce que cette syntaxe signifie est que si ce programme est exécuté directement, pas quand il est importé ou quoi que ce soit, juste un de ce programme est spécifiquement exécuté. C' est là que cela sera exécuté. Sinon, si nous importons ceci, alors il ne sera pas exécuté. Donc, c'est juste coordonner la syntaxe des yeux. J' aime bien ça. Et vous verrez probablement cela dans beaucoup de programmes Python. Bien sûr, ce n'est pas complètement nécessaire, mais c'est plutôt sympa si vous voulez tester le code que vous écrivez ici lui-même quand il veut l'exécuter. Mais sinon, si vous voulez l'importer, vous ne voulez pas qu'il soit exécuté. Bon, donc nous avons notre fonction principale ici. Et fondamentalement, ce que nous allons faire, c'est que nous
allons écrire , eh bien, deux fonctions. La première fonction va calculer la somme des carrés. Donc, nous allons l'appeler def, calculer les carrés de somme et il va avoir une entrée. On peut juste dire n pour l'instant. Nous définirons ça dans une seconde. Et notre deuxième fonction va juste dormir un peu. Et puis nous allons juste fournir, et ici l'entrée et les secondes pour combien de temps nous aimerions qu'il dorme. Et nous allons définir cela dans une seconde aussi, parce que d'abord nous avons juste besoin d'importer le module de temps, qui nous permettra de faire ce sommeil. Donc je veux dire fonctionnelle modifier ça en une seconde. Donc pour dormir un peu, tout ce qu'on va faire ici c'est qu'on va appeler la fonction sommeil. Et on va dormir pendant autant de secondes. Pour calculer la somme des carrés, nous allons juste avoir une variable de carrés de somme que nous allons initier à 0. Nous allons avoir une boucle for pour I à portée. Et, et dans chaque itération, nous allons juste avoir notre somme de carrés ajouter sur ce nombre au carré. Et puis à la fin, nous allons juste imprimer la somme des carrés ici. D' accord ? Alors maintenant, dans notre fonction principale, Allons-y et avons 24 boucles. Je dirai que pour moi dans la plage 5, nous allons juste exécuter la somme des carrés de calcul. Et cela va être notre contribution ici. Et nous allons avoir une deuxième fonction qui va dire pour moi à portée, à partir d'une, aller au sexe. Donc, nous dormons la première itération, nous allons appeler le sommeil un peu. Et nous allons avoir notre valeur, j'ai entendu dire. Et nous allons aussi avoir des minuteries que nous voulons mettre en place. Nous allons donc mesurer les temps de calcul de notre programme. Et nous pouvons également utiliser le module de temps pour cela. Donc, nous allons avoir notre heure de début de calcul va être définie comme l'horodatage actuel à ce moment. Et puis une fois que cela sera fait, nous allons dire que le calcul de la somme des carrés a pris. Et puis nous allons prendre le temps au moment actuel moins l'horodatage que nous avons en ce moment. Et nous avons d'abord sauvé notre variable ici. Maintenant, cela va nous donner une sortie avec beaucoup de nombres décimaux. Donc ce qu'on va faire à la place c'est qu'on va utiliser la méthode ronde, et on va juste l'arrondir à une décimale,
endroit pour obtenir ce genre de réduction un peu, un peu plus propre. Et après ce qu'on va faire pour dormir, on va faire une chose similaire. On va dormir, commencez. temps, qui va aussi être juste le suivi, le temps en ce moment, les
enregistrer à une variable. Et là encore, nous allons dormir. A pris l'heure actuelle moins l'heure de début. C' est le temps que ça a pris. Et pour que les calculs prennent un certain temps. Nous ne allons pas seulement vous mettre dans l'oeil, mais allons de l'avant et faisons en sorte que ce soit I plus 1, tout d'abord. Et puis nous allons aussi le multiplier par 1 million, juste pour que cela prenne un peu de temps. Maintenant, on peut faire ça. Il suffit, par exemple, de cliquer sur le bouton Exécuter ici. Et il va, eh bien,
commencer à exécuter le programme séquentiel pour nous. Et donc nous pouvons voir ici actuellement la somme des carrés est au travail et a pris environ sept secondes, arrondie à une décimale que nous pouvons voir ici. Et maintenant, notre programme va juste dormir itérativement. Donc 1 seconde, 2 secondes, 3 secondes, 4 secondes, 5 secondes. Et à la fin de ça, on va voir, d'accord, donc tout le processus a pris 15 secondes. Donc, au total, notre programme a pris environ 21 secondes ou 22 secondes. Tu en as 15 ici plus 7. Sept d'entre eux étaient pour le calcul et 15 d'entre eux pour le sommeil. D' accord, donc c'est un programme séquentiel. Alors allons de l'avant et essayons d'ajouter un peu de concurrence ici. Nous allons utiliser le threading pour cela. Donc, nous allons importer le threading. Maintenant, la bonne chose est, threading fait partie de l'installation standard de Python. Donc, vous n'avez pas vraiment besoin de pip installer quoi que ce soit d'autre. Vous pouvez simplement l'importer directement. Maintenant, pour chacune de ces boucles ici, nous allons maintenant remplacer ceci à la place par un thread. Donc, nous allons faire dans chacun de ces cas, est que nous allons créer un thread et nous l'appellerons t, va juste être notre variable courte pour thread, thread point
menaçant et autres variables que nous devons définir ici. La première chose est la cible, qui va être la fonction qui doit être exécutée. Et pour cela, pour ce cas, il va être de calculer la somme des carrés. Notez que je ne mets pas les parenthèses à la fin. C' est juste le nom de la fonction parce que nous ne voulons pas encore l'appeler. C' est un peu la référence à la fonction. Ensuite, nous pouvons également fournir les arguments de notre fonction. Nous avons un mot-clé séparé ici, args, et cela attend un tuple. Donc, puisque nous n'avons qu'un seul argument d'entrée, nous allons avoir notre valeur d'entrée ici. Et puis nous allons o. avons notre, définissons notre valeur maximale va être ceci ici, juste pour l'avoir et ne pas être un peu plus court. Et donc notre tuple d'entrée va être ceci, mais dit que ce doit être un tuple. Nous devons mettre une virgule supplémentaire ici pour nous assurer que c'est un tuple de taille 1. Ensuite, nous allons commenter cela. Et puis on va faire la même chose ici. Nous allons créer un fil de discussion. Et on va le faire cibler un peu le sommeil. Et l'argument d'entrée qu'il va fournir est cet œil ici. Et renommons ça en quelques secondes. Nous n'avons pas besoin de savoir que ces noms sont les mêmes. On n'a pas besoin de ça. Cela rend juste un peu plus agréable à lire. Donc, je vais renommer ceci en quelques secondes à nouveau, faire de ceci un tuple unique. Et nous allons le commenter. Maintenant, si nous faisons
ça, ce sera un peu surpris parce qu'en fait rien ne va encore les avoir. Et la raison en est que nous avons réellement besoin d'initier les threads. Donc, la prochaine chose que nous devons faire est pour chaque thread devra appeler t dot. Commencez. Comme ça. Maintenant, on peut faire ça et on va toujours obtenir un peu bizarre résultat. Alors allons-y et voyons ça. Alors remarquez comment notre programme a continué. Et puis nous avons les sorties d'impression. Et puis c'est là. Et puis on a fait imprimer les sommes. Donc, ce n'est évidemment pas combien de temps votre programme a pris parce qu'il y a encore d'autres choses qui se passent. Mais c'est juste parce que les threads s'exécutent simultanément. Donc, ce que nous voulons, c'est ce que nous voulons que le programme soit bloqué pour attendre que tous les threads finissent. À ce stade. C' est alors que tous les threads doivent se terminer. Et puis nous voulons imprimer combien de temps cela a pris. Donc, pour ce faire, nous allons mettre en place une, une autre variable. Que ce soit une liste. Nous allons garder une trace de chacun de ces threads et ensuite assurer
que notre programme bloque jusqu'à ce qu'ils soient tous finis. Donc, nous allons juste appeler cette variable menaces actuelles. Et encore une fois, tu peux l'appeler n'importe quoi. Et chaque fois que nous créons un thread, nous allons ajouter ici le thread afin que nous puissions le référencer plus tard. Maintenant, nous allons faire une boucle sur notre liste. Et pour chaque élément, qui est le fil ici lui-même, nous allons appeler dot join. Maintenant, ce que la jointure point fait est que bloque l'exécution jusqu'à ce que ce thread soit fait. Donc, nous itérons sur cela et nous appelons fondamentalement dot join, qui signifie que rien n'est autorisé à se produire tant que ce thread n'est pas terminé. Donc ça ne peut pas aller plus loin que ça, fondamentalement. Donc nous avons fait ça pour ici. Allons-y et faisons la même chose ici. Donc, réutilisons simplement cette variable et réutilisons ceci. Laisse-moi mettre ça ici. Et encore une fois, nous allons appeler dot join pour nous assurer que notre programme est bloqué. Et puis nous attendons que cela se termine jusqu'à ce que nous exécutions ensuite ceci. Donc si nous allons de l'avant et exécutons ça maintenant, nous pouvons voir maintenant, d'accord, donc notre exécution se déroule comme prévu. Et maintenant, nous avons notre sommeil,
ok, donc quelque chose d'intéressant à remarquer. Tout d'abord, entendez celui-ci un peu plus vite, mais, vous savez, vraiment rien à craindre. Et vraiment c'est juste parce que c'est, c'est une méthode intensive de calcul. Et donc la plupart du temps, vous n'allez pas vraiment obtenir améliorations
de performance en termes de choses comme juste des choses de calcul ici. Donc vraiment rien qui est tout fascinant ici. Et si nous voulions accélérer les améliorations dans cette section, nous allons devoir passer au multitraitement car nous pouvons utiliser différents cœurs. Mais ici parce que chaque type
de thread ne peut être exécuté qu'à la fois et que c'est intensif CPU, vraiment tous ces calculs, il n'y a pas beaucoup d'E/S en cours. Euh, donc, tu sais, ça arrive en gros de façon séquentielle de toute façon. Mais la chose cool est ici, et le sommeil est que la maladie est un exemple très, très simple. Le sommeil se produit sur un niveau de thread, donc un thread différent peut s'exécuter pendant que chacun de ces threads est inactif. Donc, plutôt que de prendre un temps total de 15 secondes, qui est ce que notre programme séquentiel a pris. Cela ne prend que cinq secondes, ce qui est fondamentalement le plus long sommeil que nous ayons eu. Le maximum ici est de cinq. Donc, nous pouvons voir dans ce cas, bien sûr, c'est l'exemple très, très basique. Nous allons être beaucoup plus utiles pour ne pas dormir ou programmer. Mais au lieu de cela, vous savez, si c'est une sorte de connexion réseau,
comme faire une requête API, écrire dans une base de données à partir d'une base de données ou,
vous savez, quoi que ce soit d'autre,
quoi que ce soit lourd dans les E/S réseau que passe juste là où nos threads sont, où notre programme passe beaucoup de temps à être inactif, juste à attendre la communication réseau et peut-être que le serveur de l'autre côté
fasse son truc puis renvoie la réponse. Maintenant, nous avons un peu vu les bases de la création de threads ici pour différentes fonctions, mais je voulais vous montrer d'autres choses que je pense intéressantes. Donc, la première chose est ce qui se serait passé si au lieu d'appeler rejoindre à la fin ici, nous l'appelions à la place ici. Alors allons de l'avant et appelons t dot joindre ici. Et allons-y et réexécutons ça. Alors que se passe-t-il dans ce cas ? Maintenant celui-ci appelle toujours la jointure à la fin ici. Mais encore une fois, c'est comme un CPU. La fonction ou intensive dans les guillemets bien sûr, mais vous savez, CBO concentré. Donc, vous pouvez le voir ici essentiellement sept secondes, qui est exactement ce que nous avions avant. Encore une fois, nous ne nous attendons pas à un changement ici. Mais dans ce cas, ce qui se passe est l'appel Join ici signifie en fait que l'exécution est bloquée. Non, cette boucle ne continue pas. L' exécution est bloquée jusqu'à ce que ce thread se termine. Donc maintenant, nous revenons aux 15 secondes qu'on avait avant. Parce que nous ne démarrons pas tous ces threads et les laissons s'exécuter ,
puis bloquons le programme à la fin jusqu'à ce que tous ces threads soient terminés. Mais au lieu de cela, nous commençons un thread, puis nous
bloquons toute l'exécution jusqu'à ce que cette menace soit faite. Alors qu'avant de commencer tous les threads ,
puis nous avons bloqué l'exécution jusqu'à ce que tous les threads aient fait. Donc, vous pouvez voir ici même juste une légère syntaxe d'avoir la jointure ici au lieu d'ici. Dans ce cas, un très grand impact sur nous. Il y a une autre chose que je voulais te montrer. Si nous retirons les déclarations conjointes, qui est en fait ce que nous n'avions pas commencé. Et si on se souvient juste, si on réexécute ça, on a une sorte de truc bizarre où on, tu sais, le programme fait son truc, le fil principal ici. Et maintenant nous obtenons toutes les impressions et en fait le sommeil se passe aussi pour ces différents fils. Donc, nous avons 10 threads différents en cours d'exécution cinq à partir d'ici. Eh bien en fait 11 parce que ce sera notre principal ici, le programme principal, nous créons cinq threads supplémentaires ici. Cinq fils supplémentaires ici. Et celui-ci finit comme, vous savez, faire son truc, il n'est pas bloqué par ça, fait ces impressions, et puis celui-ci est en cours d'exécution. Et c'est imprimer la somme des carrés. Et en attendant, ces cinq fils dorment. Nous n'imprimons aucun sens, donc nous ne le voyons pas. Donc quelque chose que vous pouvez aussi arriver est que vous pouvez ajouter un démon fly ici et définir ceci pour être vrai. Et on peut faire la même chose ici. Maintenant, cela devient intéressant quand nous exécutons ceci. Parce que ce qui se passe est que nous courons à travers le thread principal et une fois le thread principal terminé, l'ensemble du programme s'arrête. Donc, ce que signifie le drapeau du démon ici, c'est qu'une fois le thread principal terminé, tous les drapeaux Damon Autor. Et peu importe s'ils finissent ou non. Si un thread n'est pas un thread de démon, alors chaque thread doit se terminer. Tous les non-Damon menacent de finir avant que tout le programme ne puisse finir. Mais les threads Damon n'ont pas besoin de terminer pour que le programme se termine. Une fois que le thread principal est fait, alors si des threads de démon ou à gauche, cela n'a pas vraiment d'importance. Ça n'empêche pas le programme de finir. Donc c'est une chose intéressante, vous savez, selon la situation que vous pouvez ou même vouliez ou vous ne voulez pas. Mais sachez simplement qu'avoir le vol de déclaration ici signifie que ces threads, si le programme se termine, le programme principal se termine. Et si quelque chose est un thread de démon, alors cela signifie qu'il ne se terminera pas, il s'arrêtera juste, le programme est fait. Alors que si nous avons le drapeau Daymond à false, alors ces threads doivent également finir jusqu'à ce que l'ensemble du programme puisse finir, qui est exactement ce que nous avions auparavant. Alors pendant que ça marche, laisse-moi juste remettre ça. Maintenant, il y a bien sûr une chose intéressante que nous pouvons utiliser avec les articulations. Si nous avons joint, encore une fois, la déclaration conjointe signifie que le thread
sur lequel chacun de ces threads que nous appelons la jointure doit finir avant de pouvoir continuer à ce stade, car il bloque essentiellement jusqu'à ce que tous ces threads soient faits. Donc, si nous réexécutons cela, malgré que ce soit des threads Damon, parce que nous appelons ces déclarations conjointes qui bloquent la poursuite de l'exécution. Nous veillons essentiellement à ce que les programmes soient terminés. Donc on peut voir que nous revenons en quelque sorte aux résultats précédents que nous avons obtenus. Et nous pouvons aller encore plus loin pour dire, plutôt que de passer sur les fils d'Oliver, peut-être que nous ne bloquons que jusqu'à ce que les trois premiers soient terminés. Et donc notre sommeil ici. On s'attend à ce que ce soit trois secondes puisque les deux autres sont des menaces de Damon. Et pour que ça puisse continuer. Mais les trois premiers vont en fait dormir et vont bloquer l'exécution. Donc vous pouvez voir ici que c'est exactement ce que nous obtenons. Les trois premiers bloquent l'exécution une fois le troisième thread terminé de cette section, qui est un sommeil pendant trois secondes, le contingent de programme continue, il se termine, et les seuls threads restants sont des threads Damon. Donc, tout le programme est terminé.
4. Créer un cours de filtrage: Bon, donc on vient de finir d'écrire notre premier genre de programme fileté. Maintenant, ce qu'on va faire, c'est qu'on va se serrer un peu et qu'on va en faire des cours. Et je vais vous montrer comment nous pouvons réellement utiliser des classes pour le threading. Donc, pour le faire sur d'abord va réellement créer un nouveau répertoire. Et ici, nous allons juste avoir nos différents travailleurs sont des fils différents juste pour, vous savez, avoir une structure. Et puis ici, cela va être notre somme ou calculer la
somme des carrés fonction va fondamentalement être mis dans une classe afin que nous puissions réutiliser. Cela n'a pas beaucoup de sens pour ce cas d'utilisation, mais pour d'autres fins plus générales. Donc, cela va être r carré, certains travailleurs dot py, juste au cas où nous voulons en avoir plusieurs. Et celui-là, nous allons en avoir un autre qui sera votre fonction de sommeil. Donc nous allons l'avoir r, Sleep être marqueurs. Et je vais aussi à et,
et soulignement, underscore, underscore, underscore, underscore dot py fichier, qui va transformer ce répertoire ici pour
moi en un module Python à partir duquel je peux importer. Donc, n'avez même pas besoin de mettre quoi que ce soit ici, mais cela va juste me permettre d'importer à partir de ce répertoire. Bon, alors allons de l'avant et commençons par r au carré. Un travailleur. D'abord, nous allons importer le threading. Et puis on va créer une classe. Ça va être un travailleur de somme au carré. Et ce travailleur va hériter de la menace de point de thread. Donc, c'est un peu hériter de la classe de thread ici. Et puis nous allons définir l'initialisation de la classe. Et nous allons utiliser ce mot-clé super. Habituellement, il suffit de le compléter automatiquement. Alors on y va. Et nous allons à pour l'initialisation de la classe parent, nous allons juste utiliser la super méthode. Maintenant, la super méthode ici, nous définissons juste la classe que les parents ont que nous voulons initialiser. Et puis nous appelons moi ici et ensuite nous appelons point dedans. Et fondamentalement toutes les classes parents cette classe hérite seront alors initialisées. Nous n'avons donc pas besoin d'initialiser chaque classe parente séparément. Nous pouvons simplement appeler l'initialisation complète de toutes les classes parents comme ceci, ce qui est assez pratique. Dans ce cas, bien sûr, nous n'avons qu'une seule classe, mais, vous savez, si nous en avions plusieurs ici et que nous voulions simplement les
initialiser sans aucun autre problème. Alors on peut le faire comme ça. D' accord ? Et ce que nous avons ici c'est que nous allons avoir une somme de carrés calculés. Donc on va prendre le relais. Et parce que c'est une classe, nous devons mettre ici moi. Et donc toute cette méthode ici va faire, c'est qu'elle va calculer la somme des carrés exactement comme nous l'avions auparavant. Maintenant, il y a en fait deux façons différentes d'y arriver. Une façon est que nous pouvons laisser l'entrée ici afin que nous puissions simplement le fournir via cette méthode de classe. Ou l'autre façon de le faire est que nous pouvons l'avoir fait partie de l'initialisation de la classe. Et puis nous pouvons définir un attribut de la classe. Et puis nous n'avons pas de commentaires ici. Et il est humide, il suffit de référencer l'attribut. Maintenant, dans ce cas, ça n'a pas vraiment d'importance. Il peut être plus propre de l'utiliser ici. Mais au lieu de l'avoir comme ça est en fait une sorte de syntaxe que j'aime beaucoup. Parce que alors, vous savez, si vous écrivez une autre méthode, ils finissent par avoir comme beaucoup de paramètres d'entrée. Et donc de cette façon, vous pouvez simplement initialiser vos valeurs. Votre QI peut simplement initialiser votre classe pour toutes les valeurs et ensuite simplement référencer des paramètres internes plutôt que d'avoir à les transmettre à toutes ces méthodes différentes si cela arrive à ce point. Donc, nous allons réellement utiliser cette méthode. Et maintenant, il y a autre chose que nous pouvons faire, c'
est-à-dire que nous pouvons faire des quarks étoiles. Et donc ce que cela signifie, c'est que cela va être un mappage de paires de valeurs
clés pour des arguments de mots-clés supplémentaires que nous pourrions vouloir transmettre. Cela pourrait être, par exemple, le nom est égal, puis quel que soit le nom d'entrée. Et puis on peut avoir, tu sais, comme Persona. Je ne sais pas d'où cela vient, mais, vous savez, vous pouvez juste avoir tous ces autres paramètres d'entrée. Et plutôt que de définir chacun des types de montagne de la laisser ouverte, nous pouvons en fait avoir juste ce soit cette étoile, mot clé étoile, arguments. Et peut-être qu'il y a des paramètres que nous voulons réellement passer dans le thread que nous voulons définir. Et donc nous pouvons simplement passer ces arguments de mots-clés plus loin ici. Et donc de cette façon, c'est vraiment sympa parce que nous pouvons fournir tous ces paramètres d'initialisation qui peuvent simplement être transmis aux méthodes parents ou nous pouvons aussi les utiliser nous-mêmes. Maintenant, quelque chose d'autre, bien sûr, que nous devons faire, c'est que nous devons commencer notre discussion. Nous devons donc le faire pour nous assurer qu'il commence à fonctionner. Maintenant, la chose intéressante est quand nous démarrons le fil, vraiment si vous voulez faire le calcul, nous devons le mettre dans la méthode run. Donc, si nous avons une méthode run et si nous
appelons self.age star parce que nous héritons de la classe de thread. Il va démarrer le thread et je vais juste commencer à exécuter la méthode run. Et donc nous pouvons écraser la méthode run que nous héritons de la classe thread pour faire la course pour nous. Donc dans ce cas, en fait, ce que nous allons
faire , c'est juste calculer la somme des carrés. Donc, nous n'allons même pas appeler cette méthode. Nous allons juste créer la classe et ensuite il va effectuer la course pour nous. Très bien, donc encore une petite chose de syntaxe ici. Je vais juste ajouter un trait de soulignement parce que juste pour indiquer que c'est un peu comme une méthode interne que nous allons utiliser, vous savez, en interne en classe. Bon, donc ça va être notre classe de filetage, 4 carrés, un marqueur. Maintenant, allons de l'avant et faisons la même chose pour notre Yorker de sommeil. Donc encore ici, nous allons importer le threading. Nous allons créer le marqueur somnolent de classe, qui va hériter du thread de dock de thread. Nous allons initialiser la classe et initialiser la classe parent. Et nous allons autoriser les arguments de mots-clés que nous allons
transmettre aux initialisations des classes parents. Et puis aussi ici où nous pouvons mettre en est quelques secondes pour combien de temps ? Pendant combien de secondes nous voulons que ça dorme, qui est, bien sûr, nous allons utiliser une seconde. Donc, nous allons dormir ici. Une petite fonction, qui va juste appeler le temps de sommeil point sur la variable secondes. Maintenant, vous remarquerez une bonne chose que PyCharm a fait ici pour moi, c'est que nous n'avons pas importé le livre du module de temps parce que, vous savez, il est facilement disponible. Vous voulez reconnaître cela comme une option que nous l'utilisions,
cela a fait l'important pour moi, mais sinon bien sûr, vous savez, assurez-vous d'importer le module de temps. Bon, donc on va dormir pendant le nombre de secondes qu'on a passées dans l'initialisation ici. Et puis nous allons juste remplacer la méthode run pour appeler sleep,
une méthode littérale que nous venons de définir ici. Bon, donc en revenant à notre fonction principale, on n'a plus besoin de filetage et on le met ici, je pense que tu nous reverras. Nous allons, des travailleurs, des travailleurs endormis, nous allons importer notre ouvrier de la ville. Et des travailleurs point au carré
d' un travailleur que nous allons à Concord R carré un travailleur. D' accord, donc maintenant nous pouvons remplacer la création de cette boucle ici à la place par juste initialiser notre classe. Donc nous allons avoir notre ouvrier endormi être un exemple de travailleur endormi. Et nous allons vouloir un espoir qui va au-dessous. Ici. Nous avons r carré, un travailleur, qui va être une instance de la racine carrée un travailleur. Et nous allons avoir la valeur maximale ici comme paramètre d'entrée. Et ce que nous allons faire maintenant pour la jointure est pour les threads actuels. Renommons ceci en grumeaux de travailleurs actuels. Techniquement, la même chose que nous avons ici. Nous allons garder une trace de notre travailleur que nous avons initialisé ici. Et encore une fois, nous allons juste appeler la méthode join ici
à une sorte de bloc jusqu'à ce que cette exécution de cela fait. Et puis on fera la même chose pour notre ouvrier endormi. Et voici, les secondes vont être les secondes que je donne ici. Et cela, nous pouvons commenter afin que nous puissions le faire référence en une seconde. Et là encore, nous pouvons simplement changer cela pour être nos travailleurs actuels, ce qui va inclure chacun des cas que nous avons ici. Et puis on va juste appeler dot join à nouveau ici. Bon, alors allons-y et lançons ça. Alors. Je reconnaîtrai cette AMI, on devrait faire exactement la même chose. Et on dirait qu'on a rencontré un problème ici. Voyons donc où le problème est sur nos méthodes de jointure ici pour dire que nous ne pouvons pas joindre une menace avant qu'elle ne commence. Donc probablement oublié de démarrer le thread interne ici parce que nous ne l'appelons plus ici. Allons-y et essayons encore une fois. Très bien, on y va. Donc, nous avons notre sortie d'exécution ici, et nous avons notre sommeil, ce qui n'est actuellement que trois secondes depuis toujours. J' ai toujours cette syntaxe ici, le moins deux. Donc nous pouvons voir ici que nous étions juste, vous savez, dans ce cas, c'était assez simple. Nous avons juste pris ses deux fonctions ici et mis chacune d'elles dans une classe distincte, ce
qui, bien sûr, n'a pas beaucoup de sens pour cette affaire. Mais si vous faites des choses complexes comme, vous savez, vous voulez écrire des valeurs spécifiques dans une base de données. Et une partie de ce processus consiste à structurer toutes les valeurs et à les mettre en forme pour qu'elles soient dans la bonne structure, puis à les télécharger dans la base de données. Ensuite, si vous avez un travailleur de base de données spécifique peut simplement mettre dans les valeurs brutes et il va simplement structurer les données pour vous. Et puis nous allons effectuer le téléchargement. Et tout cela est un peu caché de notre fonction principale est pris en charge dans chaque classe elle-même. Et bien sûr ici, nous appelons toujours les points jointes dans chacun de ces juste pour bloquer l'exécution. Maintenant, on peut voir ici ou on ne peut pas construire. On verra dans une seconde. Rappelez-vous que nous avions ces paramètres Dan et nous pouvons toujours faire la même chose parce que nous transmettons les arguments des mots-clés. On peut donner à Damon la valeur vraie. Et puis parce que notre travailleur endormi accepte tous ces arguments de mots-clés et les transmet, il va prendre cela parce que c'est un argument de mots-clés ou de trouver une valeur spécifique, il va prendre ceci et le transmettre au parent qui dans ce cas c'est juste le thread. Donc, il va définir le paramètre du démon sur true,
ce qui bien sûr, nous pouvons voir l'efficace si nous supprimons l'appel de jointure ici. Alors allons de l'avant et exécutons ceci une fois de plus juste pour voir l'effet de l'
ajout de ce paramètre d'arguments de mot-clé en haut ici. Donc, vous pouvez voir ici le paramètre stamen a ensuite été transmis au parent parce que nous n'appelons plus la méthode join, nous obtenons exactement la même chose que nous avons vu dans la leçon précédente. Maintenant, une autre chose que nous pourrions aussi faire est si nous voulions juste avoir toutes ces classes toujours être des démons. Nous pouvons également définir le paramètre démon ici, ce qui aura le même effet. Sauf bien sûr, dans ce cas, la logique nous est cachée, qui peut ne pas être la meilleure chose, et nous n'avons pas vraiment beaucoup de contrôle sur elle à moins que nous
sachions spécifiquement ce que nous recherchons et que nous mettons à jour l'attribut de la classe lui-même. Mais en fait quelque chose d'important à savoir est que le paramètre démon doit être défini avant d'appeler la méthode start. Donc, parce que nous appelons aussi start ici, si nous prenons notre travailleur et définissons Daymond sur false, cela ne fonctionnera pas parce que le paramètre humide doit être défini avant de démarrer le thread, ce que nous verrons dans un deuxième ici. Alors, oui, on y va. Nous obtenons l'erreur pour cela. Donc, bien sûr, vous savez, cacher ce n'est pas la meilleure chose et c'est mieux si nous voulions le
faire, de le transmettre avec l'option d'argument mot-clé que nous avons ici. Et dans ce cas, nous le rendons juste un peu plus propre parce que ces fonctions, tout d'
abord, ne sont plus ici, mais il existe des méthodes de la classe elle-même. Et, vous savez, toute cette logique est en quelque sorte transmise
à chacun des différents travailleurs entre guillemets que nous avons ici, ils font tous leur propre travail séparé, responsable d'une chose distincte ou spécifique. Et alors on dit juste, d'accord, on va fuir, cet ouvrier va faire ça. Et on n'a pas appelé la jointure à la fin ici. On va les diriger. Ça va faire une chose précise. Et vraiment le programme principal est juste pour l'ordre d'exécution et la logique générale. Alors que tous aiment les gros trucs de traitement. Nous n'avons pas besoin d'encombrer ce fichier et de le rendre très volumineux. Nous pouvons en quelque sorte mettre chacun dans des fichiers séparés ou dans des classes séparées ici. Et puis, vous savez, si nous devons examiner la logique spécifique, alors tout sera contenu dans ce seul fichier. Tout ce qui est pertinent pour l'exécution de chacune de ces classes.
5. Créer un lecteur Wikipedia: Bon, maintenant que nous avons créé les bases d'avoir nos cours de threading. Allons de l'avant et sautons dans le projet réel que nous voulons
faire pour mettre en œuvre ce threading et un moyen plus utile. Donc ce qu'on va faire, c'est qu'on va prendre la liste des entreprises
S et P 500 sur cette page ici. Et nous allons juste faire défiler tous ces symboles. Et puis pour chaque symbole que nous avons ici, nous allons juste visiter la page correspondante de Yahoo Finance. Et nous allons juste extraire ce prix actuel juste ici. Et puis nous allons enregistrer ces choses dans une base de données. Donc, le processus que nous avons ici est fondamentalement que nous avons trois choses en cours qui peuvent fonctionner de façon indépendante. Et il va y avoir beaucoup de choses
sur le réseau que nous ne voulons pas vraiment être bloqués par. Donc la première chose que nous pouvons faire, c'est que nous pouvons juste prendre la liste des entreprises d'ici. Et ce que cela implique, c'est juste une demande à ici. Et puis il suffit de faire défiler cette table et toujours juste de sortir la première entrée. Une fois que nous avons chacune de ces entrées, nous pouvons alors faire une demande ici sur le site et obtenir cette valeur. Donc, c'est juste une requête réseau qui attend cette valeur, en quelque sorte l'extraire. Et une fois que nous avons cette valeur, nous pouvons l'insérer dans la base de données. Donc, nous pouvons voir que ce serait probablement une très bonne application pour le threading si nous voulons rendre cela aussi rapide que possible, parce qu'il y a un tas de choses de réseau qui se passent, vous savez, chargement de pages en attente, insertion dans la base de données, attendant la confirmation. Et il n'y a pas vraiment beaucoup de tâches CPU en cours. Donc, oui, pour ce faire, nous allons juste commencer par écrire la classe qui nous
permet d'extraire les entrées d'ici. Donc, chez nos travailleurs, je vais créer un nouvel ouvrier ici. Et on l'appellera un travailleur Wiki. Et pour cela, nous allons utiliser la bibliothèque de requêtes pour faire réellement les requêtes. Et nous allons aussi utiliser Beautiful Soup. Si vous n'êtes pas familier avec Beautiful Soup ou si vous l'avez un peu oublié et assurez-vous vérifier à nouveau la classe de mise au rebut Web. Mais sinon, la bibliothèque est assez simple. Donc juste en train de passer avec ça ici. Il devrait être relativement simple de suivre. Nous allons avoir notre classe de travailleurs wiki ici. Et nous allons avoir notre méthode d'initialisation. Et vraiment ce que nous pouvons faire ici, c'est pour l'instant, nous pouvons juste coder cela pour être une URL dont nous voulons frotter. Je vais juste copier ça. Et vraiment quand nous créerons notre classe, tout ce que nous allons faire c'est que nous allons juste avoir son yuan ou L,
le, vous savez, cet attribut de classe. Donc la prochaine chose que nous allons faire est de créer une méthode de classe qui va
être obtenir des entreprises S et P 500. Et ce que ça va faire, c'est que ça se passe trop bien. Comme la méthode l'implique, elle va nous chercher celle de l'entreprise. Donc, nous allons faire une demande. Nous allons utiliser la bibliothèque de requêtes, faire une requête GET à notre URL ici, comme ceci. Et nous allons juste supposer que tout se passe, mais nous pouvons juste avoir ici et comme si notre code d'état n'est pas à 100 et que je vais retourner une liste vide et peut-être que nous pouvons imprimer comme je ne pouvais pas obtenir. Et les arbres, tu sais, peu importe. C' est juste une sorte de base. Bien sûr, vous pouvez étendre cela à tous les différents codes d'état dont vous voulez vous soucier ou même faire un peu de journalisation ici, mais nous aurons juste cela pour le strict minimum. Et puis nous allons utiliser, plutôt que d'avoir tout dans la même méthode, allons juste de l'avant et créer une deuxième méthode qui va réellement extraire les symboles de la société. Et cela va prendre dans la page HTML. Et cette méthode ici va être la chose qui va réellement être responsable de sortir chacun de ces symboles. Alors allons de l'avant et regardons la source de la page, que vous pouvez faire soit en cliquant avec le bouton droit ici et afficher la source de la page ou Commande Alt J. Et nous
cherchons, Allons-y et obtenons une compréhension de la structure. Alors, cherchons le premier symbole ici, qui va juste être M. Et si on effondre
ça, c'est la table que nous recherchons. Et cette table en fait assez agréable comme nous pouvons le voir. Il y a donc une idée associée à cette table. Et si nous regardons cela, alors nous pouvons voir que c'est le seul identifiant de cette table. Donc il n'y a regard sur nous ou quelque chose comme ça non plus, ce qui est très gentil. Alors oui, allons de l'avant et créons nos belles boucles. Belle instance de soupe, qui va prendre la page HTML. Et on va utiliser le Lx. je vais analyser. On va juste mettre ça ici parce que si on ne met pas ça ici, on va juste recevoir un avertissement ou même pas un avertissement, comme une notification. On peut l'oublier une seconde juste pour voir. Mais oui, juste en spécifiant ceci pour qu'on n'obtienne pas cette journalisation, ce qui peut être un peu ennuyeux. D' accord, donc la prochaine chose que nous devons faire est trouver cette table de contenu d'abord, puis nous allons faire une boucle sur cette table. Donc notre contenu ou notre table va être soupe dot find. Et nous allons trouver par la carte d'identité, qui va être les électeurs. Et je vais juste passer en revue cela un peu plus vite puisque cela comme quelque chose de raclage web, pas nécessairement concentré sur le thread, mais juste pour que nous ayons un travailleur disponible pour nous qui peut réellement obtenir ces contenus afin que nous puissions continuer à les utiliser. Donc c'est notre table. Et maintenant que nous avons notre table, nous voulons passer en revue toutes les rangées. Donc, nos lignes de table. Si nous allons dans notre table, nous allons trouver toutes les balises de ligne de tableau dans notre tableau ici. Donc on peut voir qu'il y en a un dans l'en-tête, et ensuite il y en a pour chaque rangée, on en a un ici dans le corps. Et puis nous pouvons faire une boucle sur nos lignes de table. Donc, nous pouvons dire pour la ligne de table dans une ligne de table et nous allons sauter la première. Parce que vous remarquerez si vous nous testez que le premier est en fait dans l'en-tête ici. Et donc bien sûr, vous savez, il n'y a pas de symbole à extraire ici, donc on va sauter le premier. Et puis pour chaque ligne de table, nous allons extraire le symbole, ce qui va être, nous allons trouver la première balise T d, que nous pouvons voir ici. Et à partir de là, nous allons retirer le texte. Et nous allons également supprimer le caractère de nouvelle ligne à la fin ici. Donc ça va être nos symboles. Et maintenant, nous pouvons soit recueillir ces mentalistes, puis retourner la liste entière. Ou nous pouvons également utiliser un générateur et juste sentir ou symbole. Et puis à partir d'ici, nous pouvons dire rendement à partir de points, extraire les symboles de la société. Et je vais juste avoir besoin de passer la page HTML DOM, qui va être juste la partie texte de notre réponse ici. Très bien, donc une chose à remarquer en fait, c'est que nous n'utilisons pas de propriété de classe ici. Et donc ce que nous pouvons faire est que nous pouvons réellement en faire une méthode statique qui appartient, est fondamentalement partagée entre toutes les instances de la classe. Et puis nous ne le faisons pas, parce que nous n'utilisons aucune propriété de classe est elle-même. D' accord. Donc ça va être notre ouvrier de Vicki. Mais bien sûr, Allons de l'avant et testons cela. Maintenant parce que nous utilisons Beautiful Soup. Vraiment. À ce stade, il devient, il y aura, un peu plus agréable si nous voulons réutiliser cela plus tard. Juste pour s'assurer que tout notre environnement, toutes nos bibliothèques et autres choses sont en quelque sorte contenus. Nous allons créer un environnement virtuel. Donc, je vais aller python moins m,
puis, puis quelqu'un pour créer un environnement virtuel. Et le répertoire actuel qui s'appellera Ben. Hit Enter, qui va créer notre environnement virtuel pour nous. Et cela nous donne simplement une sorte d'installation Python fraîche que nous pouvons utiliser, ce qui est juste si nous l'activons,
cela devient un peu plus agréable parce que alors nous sommes un peu conscients des bibliothèques
que nous utilisons et nous pouvons faire un afin que tout soit en quelque sorte autonome et ne
dépend pas de notre configuration système actuelle. Nous allons donc aller de l'avant et activer notre environnement virtuel. Et si nous allons simplement dans Python, par exemple, maintenant vous pouvez voir où dans notre environnement virtuel et j'essaie d'importer cette classe, nous avons en fait un problème parce que pour le moment nous n'avons pas belle superstorm. Donc, nous allons dire à partir des travailleurs dot wiki, worker, nous allons importer le travailleur clé 0 et même la requête n'est pas installée. Donc, nous allons aller de l'avant et faire des demandes d'installation de pip. Et parce que nous sommes dans notre environnement virtuel, va réellement utiliser la version pip de notre environnement virtuel. Vous pouvez donc voir ici le PIP pour l'environnement virtuel ici. Et puis la prochaine chose que nous voulons faire est que nous allons aussi vouloir installer Beautiful Soup. Donc, pour ce faire, nous allons taper pip, installer le OH, à soupe complète pour. Il n'y a pas de type ici. Ok, super. Et oui, ce sont les deux bibliothèques dont nous ne devrions pas avoir besoin. Pour que nous puissions aller de l'avant et essayer ça. Encore une fois et super. On y va. Ça marche. On peut tester ça en une seconde. Mais écrivons simplement nos paquets actuels dans un fichier d'exigences afin que, si nécessaire, nous puissions recréer cela plus tard. D' accord, alors allons-y et testons ce wiki et ce travailleur. Et nous allons faire une instance de n. Et puis nous pouvons dire pour le symbole dans McKee, travailleur point obtenir des entreprises S et P 500, juste appeler notre méthode de classe ici. Allons de l'avant, imprimez un symbole, et puis interrompons-l'. Génération d'une faute de frappe ici. D' accord. On va imprimer le symbole et ensuite on va se casser. Et oui, on y va. Donc, c'est un avertissement que nous obtenions ce genre de comme choisir un 12 spécifique. C' est pourquoi vous pouvez juste mettre L, X et L là-dedans. Laisse juste que ça ne les fasse pas. D' accord ? Ok, donc en regardant notre simple, d'accord, donc nous avons le premier. Et puis nous allons juste avoir une liste de symboles. Et faisons la même chose. Mais attachons chaque symbole à notre liste simple pour nous assurer que nous n'obtenons rien de plus, vous savez, à la fin ou quelque chose comme ça. Et puis nous allons regarder la longueur de notre symbolisé, qui a 505, qui est en fait le nombre d'entreprises dans ce domaine. Je sais que c'est un peu déroutant parce que ça dit 500 et c'est 505 en fait. Mais c'est génial parce que c'est exactement ce que nous attendions. Et deux, aucun supplément ne les confirme. On peut regarder le dernier. Faites défiler tout le chemin vers le bas. Une fois trop loin. On y va. Ok, parfait. Donc nous avons maintenant notre classe pour obtenir les symboles. Encore une fois, nous avons passé ça un peu plus vite juste parce que, encore une fois, nous voulons nous assurer que nous nous concentrons sur le filetage ici et pas spécifiquement sur la construction de cuivre ouest. Donc, oui, si vous êtes familier avec Beautiful Soup et lingettes, super. Et si vous ne l'êtes pas, vous auriez probablement pu suivre de toute façon, puisque notre syntaxe est assez simple ici et nous passons juste à travers différents éléments HTML. Mais si vous voulez un rafraîchissement à ce sujet, si vous voulez apprendre ce mélange, vous allez de l'avant et simplement secouer la classe de scrapping Web à nouveau. Mais oui, donc maintenant nous avons notre travail wiki sont disponibles pour nous, ce qui va être la première chose bien sûr que nous avons besoin. Ce qui va essentiellement nous voir avec toutes nos valeurs que nous pouvons ensuite utiliser pour, vous savez, plus tard, chercher les entreprises individuelles en manipulant cette URL ici. Ensuite, nous pouvons également aller de l'avant et une fois que nous extrayons cette valeur ici, nous pouvons ensuite aller de l'avant et l'envoyer dans une base de données. Alors arrêtons-nous ici pour l'instant et continuons avec ça dans la prochaine leçon.
6. Créer un ladire de financement Yahoo: Bon, maintenant que nous avons notre configuration de travailleur wiki, allons de l'avant et écrire la classe, qui va être une classe thread, qui va extraire le prix de l'utilisation de cette URL Yahoo Finance ici. D' accord, donc je vais aussi supprimer ces deux travailleurs ici parce que,
eh bien, nous n'avons plus besoin d'eux. Alors allons de l'avant et supprimez ces très rapidement. Nous allons créer un nouvel ouvrier ici, qui sera Biao qui financera le prix. On appellera ça les ouvriers de Yahoo Finance. Et puis ici, nous allons d'abord importer le threading parce que nous l'utilisons. Mais alors il aura un travailleur de prix yahoo Finance, qui va hériter du thread de point de thread, comme nous l'avons fait auparavant. Et puis dans notre méthode d'initialisation, nous allons juste nous assurer d'initialiser cela à. Et nous allons également accepter les arguments de mots-clés que nous allons
transmettre à nos classes parents ici. D' accord, donc c'est ce qu'on avait avant. Maintenant, assurez-vous également de
démarrer le thread afin que vous sachiez que nous arriverons à ce point. Et puis nous allons aussi avoir le, nous allons écraser la méthode run, mais la définir dans un peu. D'accord ? Alors de quoi avons-nous besoin ? Eh bien, nous devons aussi accepter le symbole que nous voulons avoir. Vous voulez enregistrer ce symbole en tant qu'attribut de classe. Et puis nous avons aussi besoin de l'URL de base que nous voulons utiliser, qui va essentiellement être tout sauf pour cette dernière partie. Donc, cela va être notre URL de base. Et puis à la fin ici, nous pouvons, eh bien, en fait, nous pouvons avoir notre année de base juste définie ici. Ensuite, nous allons définir l'URL réelle pour être notre URL de base. Et utilisons des chaînes formatées ici. Et puis nous allons juste ajouter le symbole à la fin ici. Donc oui, on va juste avoir notre année de base. Je serai la première partie ici. Et puis ici, nous allons ajouter sur elle sont similaires à la fin. Et donc vraiment ça va juste nous donner quel que soit le symbole. Il va juste nous donner le même résultat que celui-ci. C' est juste une façon plus nette, à mon avis, d'exprimer cela. Bon, donc maintenant nous avons notre ouvrier ici, et maintenant nous voulons écraser la méthode de course, qui est fondamentalement ce que nous devons faire ici est OK, donc maintenant nous avons cet urinoir. Donc, une fois de plus, nous devons extraire ce prix ici. Alors, allons dans le HTML et essayons de trouver ceci. Donc on l'a ici, c'est en fait dans le titre. C' est très pratique. Voyons si c'est ailleurs aussi, mais on pourrait déjà l'obtenir de là. C' est aussi ici. Et voyons si c'est bon. Donc aussi retourné dans le script quelque part. Il y a donc différentes façons d'y arriver. L' un d'eux est bien sûr, nous pouvons l'extraire. Où était-ce ? De ? Où il est apparu comme nous pouvons l'extraire d'ici. Mais si nous faisons un clic droit et nous copions le XPath, et continuons simplement et jetons un coup d'oeil à cela. Ouais, donc ça n'a pas l'air particulièrement propre. n'y a pas d'identification spécifique ou quoi que ce soit que nous puissions utiliser ici. Et comme il est également inclus dans le titre, nous ne pouvons pas simplement l'extraire de là. Ceci est bien sûr, un peu dépendant est supposé que Yahoo sorte de garder ce format. Mais, vous savez, si, s'ils changent, comme s'ils changent aussi ce format ici, nous allons aussi bien sûr devoir adapter notre éraflure ou de toute façon. Donc, allons juste avec l'option plus simple pour l'instant. On va juste l'extraire du titre lui-même ici. D' accord. Donc, encore une fois, nous allons importer à partir du dossier BS. Nous allons importer Et Belle Soupe. Et allons de l'avant et juste tester ceci ou des nouvelles cependant. Nous devons également importer le module de requêtes. Et allons-y et utilisons-la pour les tests. Donc, nous allons aller définir notre URL ici. Nous allons importer des demandes, dira, d'accord, égal point de requête obtenir notre URL. Et puis nous allons faire de notre soupe un exemple de Beautiful Soup, en
prenant le texte de nos demandes. Donc j'ai une faute de frappe ici. Je n'avais pas d'importance, important. Essaie encore ça. On va aller au titre du point de soupe, ce qui nous permet d'accéder directement à ça, non ? Donc, heureusement, il
semble que ce contenu est généré dynamiquement, mais c'est correct. Partez pour aller à ce sujet d'une manière différente. Nous allons utiliser la bibliothèque L XML à la place. Et vraiment, nous allons juste l'utiliser pour une chose très simple, ce qui va juste faire en sorte que nous puissions utiliser
XPath car il n'est actuellement pas pris en charge avec Beautiful Soup. Donc nous allons dire à partir de x, je suis L, x et L, et nous allons importer du HTML. Donc je suis, bien sûr qu'on ne l'a pas installé. Alors allons de l'avant et installons rapidement décrochage L x L. Nous
y allons. Je vais écrire ceci à une exigence. Mettez notre Python à nouveau, essayons d'importer cela. On y va. Et prenons, n'ai plus besoin de beau supérieur. Allons de l'avant et avons notre vous êtes, nous allons envoyer une demande et des demandes de sonde. D' accord. Et puis nous allons dire, eh bien, notre contenu de page que nous pouvons appeler va être HTML à partir de chaîne. Donc, nous allons juste importer du HTML ici à partir de L XML. Cela va juste nous aider à analyser en utilisant XPath. Je le suis encore, vous remarquerez que la syntaxe est très simple, donc pas besoin de se familiariser avec cette bibliothèque. Nous allons simplement utiliser ces deux méthodes. abord, nous allons mettre ici la chaîne HTML, qui va être enregistrée ici. Et puis cela a une méthode ex pat x path que nous allons utiliser. Et donc ce que nous devons faire ici, c'est maintenant que nous devons obtenir le XPath pour cela,
ce que nous pouvons faire très facilement en cliquant avec le bouton droit de la souris sur Copier XPath. Donc, une fois que nous avons trouvé cet élément ici, que nous pouvons simplement faire en cherchant comme ceci, vous pouvez cliquer avec le bouton droit de la souris Copy XPath, puis aller de l'avant et mettre cela ici. Et on y va. Donc, nous pouvons voir si nous pouvons accéder au premier élément, le texte, alors nous allons être en mesure d'extraire la valeur ici comme ceci. Bon, alors allons-y et mettons-en œuvre. Donc nous avons testé ça pour nous assurer que nous avons quelque chose qui fonctionne. Alors allons-y et refaisons-le. Nous allons avoir notre puits,
en fait, nous pouvons juste copier ça, donc depuis qu'on l'a déjà fait. Donc, nous allons d'abord émettre notre demande, qui va être à travers cela. Et puis nous avons notre contenu de page comme celui-ci. Et puis nous voulons avoir un prix comme celui-ci. Et nous ne faisons pas beaucoup de gestion des erreurs ici. Par exemple, que se passe-t-il si nous n'obtenons pas de réponse ici ? Cette valeur ne peut pas être convertie en flottant ou autre. Donc, bien sûr, vous savez, si vous voulez rendre cela plus robuste, vous pouvez ajouter la vérification du code d'état ici comme nous l'avons fait dans notre collaborateur wiki. Vous pouvez ajouter des instructions try-except pour gérer différents cas où vous ne sortez pas toujours une valeur flottante. Mais juste pour garder cela simple, nous allons juste le garder comme ça sans faire trop de gestion des erreurs. Donc maintenant, nous avons notre prix, et ensuite nous pouvons simplement aller de l'avant et imprimer notre prix pour l'instant. D' accord, alors revenons à notre fonction principale ici. Et maintenant, nous allons changer un peu la situation et importer nos deux travailleurs et les faire travailler un peu ensemble. Donc ici, nous voulons importer le travailleur des prix Yahoo Finance. Donc la première chose que nous allons faire est de créer une instance de notre collaborateur wiki. Et nous allons dire pour symbole dans le travailleur Wiki, ne recevez pas les entreprises S et P 500. Cela va juste nous donner un symbole à la fois. Et maintenant, nous allons créer une instance du travailleur des prix Yahoo Finance. Et le symbole que nous allons passer ici va juste être le symbole que nous avons ici. Et puis si nous voulons et gardons une liste de nos travailleurs actuels, comme nous l'avons fait. Penned sont Yahoo Finance, travailleur des prix. Et puis utilisez simplement la méthode join ici. Et enlevez ça. On peut encore distraire le temps. J' ai pris et renommé notre variable ici pour arrêter le temps de redémarrage. Bon, donc nous devons nous assurer d'utiliser l'instance de son collaborateur wiki ici, pas seulement la définition du coût elle-même. Alors passons en revue ce qu'on a fait. Et fondamentalement, nous appliquons ce que nous avons appris pour le filetage ici en utilisant nos deux travailleurs. Donc, le premier que nous avons est notre collaborateur wiki, qui encore une fois, si nous y passons,
il a la méthode principale que nous allons utiliser ici, qui va obtenir les entreprises S et P 500, qui va juste envoyer ce demande. Et pour cette requête des éléments de la table, C'est ceci, je vais juste extraire le premier élément,
qui, nous supposons, sera le symbole. Et que nous allons utiliser comme entrée loin Yahoo Finance travailleur prix. Et pour cela, nous allons ensuite envoyer une requête à cette URL. Nous allons extraire du HTML en utilisant cette classe HTML XML ici. Nous allons juste l'utiliser pour que nous puissions réellement obtenir le genre XPath d'avoir ce soit un moyen facile d'
obtenir le XPath un extrait du prix d'ici et le convertir en un flotteur. Donc nous allons faire défiler ces listes d'entreprises que nous avons ici. Et pour chaque symbole que nous
obtenons, nous allons alors créer un thread, qui va créer cette requête. Et puis il va juste l'imprimer à la sortie pour l'instant. Alors, nous suivons le temps d'exécution comme nous l'avons fait avant. Et ici, nous appelons jointure à la fin, juste pour que fondamentalement tout soit bloqué jusqu'à ce que chaque thread se termine. Et nous n'avons même pas besoin de faire autre chose ici parce qu'il a le, nous écrasons la méthode Run par défaut, qui se produit juste après que nous avons démarré le travailleur. Donc, oui, avant de lancer ça, je veux mettre en œuvre une autre chose qui
va juste ralentir notre périmètre. Nous allons importer du temps et nous allons importer au hasard juste pour éviter le spam. On va dire « Time dot sleep ». On va dire 200 points aléatoires au hasard. Cela signifie donc que chaque thread va dormir entre 0 et 20 secondes car cela génère un nombre aléatoire entre 01. Donc ça va ralentir un
peu les choses et ça va faire fonctionner notre programme. Eh bien, je suppose qu'à ce stade, un maximum de 20 secondes de quelque chose ne dort que 20 secondes. On peut même pousser ça jusqu'à 30 pour, tu sais, comme ne pas spamer Yahoo pendant que nous faisons ça. Parce que nous allons changer les choses un peu plus tard pour ne pas aimer créer un travailleur individuel pour chaque symbole que nous avons ici. Mais oui, et en fait je veux implémenter une vérification supplémentaire ici, ce qui va être si notre code d'état est 200. Alors pour l'instant, arrêtons-nous. Et, vous savez, arrêtez l'exécution pour que nous n'obtenions pas comme span avec les messages d'erreur et autres choses. Alors allons de l'avant et exécutons notre fonction principale. Je vais le faire sur le terminal cette fois parce que j'ai mon environnement virtuel ici, qui a tout installé dont j'ai besoin. Alors allons de l'avant et lançons ça. Et après avoir attendu un peu, On y va. Nous avons donc les prix qui commencent à arriver ici. Certains nous interrompent. Mais oui, tout fonctionne comme prévu. Maintenant, je peux vous garantir qu'il y a probablement des erreurs ici que nous n'attrapons pas, ce qui peut être dû à une variété de raisons que nous devrions mieux traiter. Mais pour l'instant, nous allons juste laisser ça comme c'est pour l'instant. On devrait au moins être comme déconnecter ça ou quelque chose comme ça. Mais quoi que ce soit pour l'instant, laissons-le tel quel, puisque le but principal de cela était juste de mettre en place les threads pour faire réellement les requêtes séparées. Donc, ce sont les threads séparés. Pour que nous puissions faire toutes ces requêtes séparées afin que nous puissions, vous savez, nous ne sommes pas bloqués par tout ce temps réseau. Mais à l'avenir, nous allons en fait voir comment nous
pouvons en quelque sorte limiter et d'échelle et définir le nombre de travailleurs que nous voulons avoir pour que chacun ait tout cela un peu plus structuré plutôt que juste frai et thread individuel pour chaque itération que nous avons ici. Et cela va également nous apprendre comment nous pouvons transmettre des informations entre différents threads afin que tous ces trucs puissent fonctionner simultanément. On y arrivera dans la prochaine vidéo.
7. Quents et programmeurs: Bon, donc dans la dernière leçon, nous avons en quelque sorte mis en place notre collaborateur Yahoo Finance ainsi que notre collaborateur wiki, ce que nous avions avant. Et nous avons juste défilé tous les symboles et envoyé des demandes et, vous savez, obtenu le prix que nous pouvions. Mais maintenant, nous allons systématiser cela et le rendre un peu plus agréable. Et ce qu'on va faire, c'est que ces processus seront séparés. Donc, plutôt que de faire défiler le symbole et ensuite pour chaque symbole créant directement un thread, ce que nous allons faire est de séparer toutes ces entités. Donc, nous allons d'abord parcourir tous les symboles. Et puis on va juste, chaque fois qu'on aura un symbole, on va juste le mettre dans une file d'attente. Et puis nous aurons différents threads des travailleurs
de Yahoo Finance qui vont lire de cette file d'attente. Donc on a un peu ce truc intermédiaire. Et oui, encore une fois, cette chose
que nous allons utiliser s'appelle une file d'attente. Et vraiment l'idée, lui, idée ici est que nous pouvons prendre des éléments et nous pouvons les mettre dans le Q. Et de cette façon, nous sommes en quelque sorte de séparer vitesse ou la lenteur des différents threads. Parce que le Q peut s'accumuler et nous pouvons mettre beaucoup d'éléments dans. Et puis nos travailleurs le peuvent, notre ouvrier en aval. Ainsi, ceux qui prennent de cette file d'attente peuvent simplement lire de la file d'attente chaque fois qu'ils sont prêts. Donc de cette façon, nous avons aussi un peu de, et nous le verrons plus tard. Nous avons plus de contrôle sur, vous
savez, le nombre d'intrants que nous aimerions avoir si nous pouvions mettre à l'échelle. Mais aussi combien comme les lecteurs de la file d'attente, combien de consommateurs de la file d'attente que nous voulons avoir. Si nous remarquons que notre file d'attente s'empile trop rapidement et qu'elle ne cesse de croître, alors nous pouvons ajouter plus de consommateurs. Et si nous remarquons que notre truc ou le q est toujours vide fondamentalement, alors nous pouvons réellement réduire le nombre de consommateurs parce que cela ne nous procure pas vraiment un avantage d'avoir autant de travailleurs. Bon, donc pour implémenter une file d'attente, nous allons utiliser la bibliothèque multitraitement. Et à partir de là, nous allons importer Q, ceci. Et puis nous allons créer une file d'attente, qui va être notre symbole Q, qui va être une instance de Q comme celle-ci. Et donc ce que nous allons faire est de commenter ceci pour l'instant. Commenter ceci ici. Pendant que nous scrutons les symboles ici, nous allons juste utiliser notre symbole q. Et ici, nous allons mettre le symbole, donc nous allons l'insérer dans la file d'attente. Maintenant, les indices sont thread-safe, ce qui est excellent parce que cela signifie que nous pouvons réellement utiliser le système fiscal de threading. D' accord, et donc, ouais, c'est tout ce qu'on a à faire de cette façon. Nous mettons des éléments dans notre file d'attente. Et donc si on fait ça et qu'on peut juste imprimer la file d'attente à la fin. Et il y a en fait une méthode get que nous pouvons utiliser qui obtient juste l'élément suivant de la file d'attente. Donc, nous pouvons exécuter notre fonction principale juste pour voir les résultats de cela. Donc, nous voyons que nous avons une file d'attente implémentée ou une instance de l'objet ici. Et en utilisant la méthode get, nous obtenons la première valeur de la file d'attente, qui dans ce cas est le premier symbole. On s'y attend. Bon, donc maintenant que nous mettons ces éléments dans la file d'attente, maintenant nous pouvons avoir un flux distinct de processus qui peuvent être consommés à partir de cette file d'attente. Et c'est ce que vont être nos travailleurs du prix Yahoo Finance. Mais nous allons aussi changer un peu les choses ici. Et au lieu d'avoir les travailleurs du prix de Yahoo Finance faire cela directement, nous allons vraiment changer cela et nous allons avoir un planificateur qui va s'occuper du threading. Et puis nous allons avoir notre ouvrier des prix Yahoo Finance lui-même juste être la classe qui extrait les informations sur les prix. Mais aura une classe différente Kino responsable de la partie multitraitement. Donc nous appellerons celui-ci le planificateur de prix de Yahoo Finance. Et cela va être une instance de course. Et ce ne sera en fait plus une sous-classe de la classe de thread. Donc, là encore, nous allons initialiser ça. Nous allons initialiser la classe parent. Nous allons également autoriser les arguments de mots-clés. Oups, et transmettez-les à la classe parent ici. D' accord, et puis nous allons remplacer la méthode run. Et là, nous allons juste avoir une boucle infinie. Et fondamentalement ce que nous allons faire dans cette boucle infinie est que nous allons juste lire dans la file d'attente. Et donc ce dont nous avons besoin ici aussi est que nous avons besoin une file d'attente d'entrée parce que nous avons besoin d'une lecture d'une file d'attente. Donc, nous allons fournir qu'en tant qu'argument d'entrée ici a un argument d'initialisation. Nous allons avoir notre file d'attente ici. Et puis nous allons avoir notre prochaine valeur juste être autodidacte file d'attente d'entrée. Encore une fois. Maintenant, c'est une opération de blocage, qui signifie qu'elle va bloquer cela, ou cette opération va bloquer jusqu'à ce que nous obtenions réellement une valeur renvoyée. On y arrivera plus tard. Mais fondamentalement, pendant que cette boucle est en cours d'exécution, il va juste essayer de continuer à lire à partir de la file d'attente. Et chaque fois qu'il obtient une valeur, alors il va continuer l'exécution. Donc aussi ce que nous voulons faire ici, c'est parce que nous avons une boucle infinie ici à un moment donné que nous voulons en sortir. Donc un moyen facile de le faire pour dire, d'accord, si nous envoyons la valeur w1 et que nous avons fini, maintenant nous voulons juste sortir. Mis à part ça. Si nous obtenons une valeur et que cette valeur n'est pas faite, nous allons supposer qu'il s'agit d'un symbole. Et alors, ce que nous voulons faire, c'est que nous voulons avoir une instance de notre agent des prix Yahoo Finance. Et le symbole que nous allons passer ici sera notre valeur parce que nous
allons nous assurer que notre Q amont met réellement la valeur ici. Et puis nous allons également changer cette méthode d'exécution. Et nous allons plutôt le renommer pour extraire ou obtenir le prix pour Spark. On l'appellera juste bon prix. D' accord ? Donc on va appeler ça, et on va dire « prix ». Et ici, au lieu d'imprimer le prix, Allons de l'avant et retournons le prix. Donc, nous allons dire que notre prix est égal à l'utilisation de l'instance de notre ouvrier Yahoo Finance ici, nous allons obtenir le prix et en fait besoin de déplacer cela ici, démarrer le fil. Et puis si nous voulons ici, nous pouvons imprimer la presse pour maintenant et plus tard, nous allons en fait mettre cela dans une file d'attente différente, qui va être responsable, quel travailleur en aval il va être responsable insertion dans la base de données. Mais pour l'instant, on va juste l'imprimer. Et Yang, on n'a plus besoin de dormir ici. Mais ce que nous pouvons faire si nous voulons faire, c'est que nous pouvons ajouter un peu de sommeil à la fin ici, puisque nous ne le sommes pas vraiment, ce n'est pas comme une requête API, ce n'est pas comme une requête API,
donc nous n'obtenons pas d'informations de l'API dans le est à peu près comme de grandes limites ou quelque chose comme ça et combien de requêtes nous pouvons faire. Donc, pour être respectueux après chaque demande, nous allons juste dormir n'importe où entre 01 secondes juste pour ralentir un peu le processus. Donc encore une fois, ce que nous avons ici, c'est que nous avons notre classe de planificateur maintenant, que nous avons un peu Déplacer pour être notre classe de thread maître. Et cela va prendre une file d'attente d'entrée comme une entrée. Et puis nous allons commencer le fil. Et puis il va fondamentalement aller dans une boucle infinie. Il va continuer à lire à partir de la file d'attente jusqu'à ce qu'il lit la valeur, à quel point il va éclater. Et chaque fois qu'il obtient la valeur et cette valeur n'est pas faite. Il va créer une instance de la classe de travailleur de prix Yahoo Finance. Il va fournir cette valeur comme symbole. Depuis la requête ou en supposant que c'est ce que nous obtenons de cette classe ici. Et puis nos jeunes travailleurs des prix de la finance vont être responsables d'en extraire le prix. Et oui, c'est tout pour l'instant. Alors allons-y et prenons ça ici. Et nous allons créer une instance à l'avance afin que,
vous savez, dès que nous commençons à mettre des valeurs jusqu'à la file d'attente, nous puissions réellement commencer à la consommer. Très bien, alors créez une instance de notre barème de prix Yahoo Finance ici. Non, vous devez vous assurer que nous donnons la file d'attente d'entrée. Maintenant, la file d'attente d'entrée que nous allons utiliser sera le symbole Q, puisque c'est là qu'il devrait lire. Donc, ouais, en ce moment, nous avons juste un fil que nous créons ici. Nous allons simplement créer une liste pour cela au cas où vous voulez en avoir plus, nous allons plus tard sur la finance, le prix, le planificateur, les loyers. Et comme ça. Et puis on peut juste garder cette boucle ici, plus besoin de ça. Très bien, donc une chose que nous devons faire à la fin ici, c'est parce que nous attendons la valeur w1. Une fois que nous avons fini, assurez-vous que nous mettons ici fait. Donc, notre classe va réellement sortir, ou ce thread est en fait une sortie. Une chose bien sûr que nous pouvons faire plutôt que simplement en mettre une, c'est si nous voulons changer cela plus tard, ce que
nous allons bientôt dire pour les boucles. Pour autant de threads que nous avons, nous allons mettre une valeur w1 pour nous assurer que chaque instance de notre thread va réellement se briser. Parce que si nous mettons juste une valeur ici, parce que nous consommons de cette file d'attente, chaque, chaque thread va juste lire une valeur. Et une fois qu'il atteint cette valeur à fait fondamentalement. Donc, donc si nous avons plusieurs threads et qu'un seul d'entre eux voit la valeur w1, alors disons que nous avons quatre threads. L' un d'eux lit fait que les trois autres threads ne vont pas éclater parce que la file d'attente est vide et qu'ils attendent quelque chose à lire. Et cela bloque simplement toute autre exécution pour ce thread pour l'ensemble du programme, juste pour ce thread. Donc je le suis, c'est pourquoi nous voulons nous assurer que nous fournissons juste assez de valeurs faites ici pour nous assurer que chaque instance de la gorge que nous avons réellement éclate. Et oui, allons-y et lançons ça. Celui-ci devrait être un peu plus lent puisque nous n'avons qu'une seule instance de notre thread. C' est exactement ce qu'on voit ici. Nous extrayons juste nos valeurs et nous mettons nos valeurs dans la file d'attente ici. Et une fois qu'une valeur commence, vous savez, est dans cette file d'attente, c'est à ce moment
que notre travailleur commence ici. Donc, il est déjà initialisé à l'avance et il commence déjà à fonctionner. Et dès que nous l'initialisons à entre dans cette boucle, et puis il le fait. Et maintenant, il attend qu'il y ait quelque chose dans la file d'attente. Une fois qu'il y a quelque chose dans la file d'attente, il va en lire. Dès que le premier symbole est mis ici, va commencer à lire à partir de lui. Si nous voulons, nous pouvons voir que nous pouvons ajouter un sommeil et disons juste dormir pendant dix secondes. Et nous pouvons dire insérer le premier symbole. Alors jetons un coup d'oeil à ça. Nous allons donc insérer le premier symbole et ensuite nous allons
attendre pour qu' un symbole soit inséré. Mais dès qu'il est inséré, il y a une valeur dans le planificateur de prix Q et R Yahoo Finance qui est déjà en cours d'exécution dès que quelque chose est dans la file d'attente, alors il peut le sortir de la file d'attente ici et il peut commencer à faire son travail. Donc, dès que quelque chose est dans la file d'attente, alors il commence à faire son travail. qui est vraiment agréable parce que ce genre de rend tous les processus indépendants les uns des autres. Bon, donc bien sûr qu'on peut l'enlever. Et maintenant, si on veut faire ça un peu plus vite, tout ce qu'on a à faire c'est juste, tu sais, disons que Num, Yahoo Finance, les agents des prix. Disons que nous voulons avoir pour les travailleurs. Et nous pouvons dire pour autant de travailleurs qu'ils veulent avoir, vous savez, nous créons juste un de ces travailleurs. Et maintenant, nous aurions dans ce cas, pour les travailleurs qui exécutent chacun d'eux en attente de lire à partir de la file d'attente. Et chaque fois que quelque chose est mis dans la file d'attente ici, ils vont commencer à en consommer et ils vont
commencer à faire leur travail, comme on peut le voir ici. Et nos files d'attente sont thread-safe, ce qui est vraiment sympa parce que, vous savez, nous n'avons pas à traiter aucun des problèmes dont nous avons parlé à l'avance. Et d'accord, alors maintenant on a de bonnes valeurs ici, accord, à qui on doit faire face. Donc le prix est trop élevé. Donc, une chose que nous pouvons faire ici est de faire un peu de formatage et d'appeler ceci le prix brut. Et on dirait qu'il y a une virgule pour des milliers. Donc, nous allons juste remplacer cela par une chaîne vide comme celle-ci. Juste pour corriger là où ce n'était pas, comme ces choses de formatage. Donc oui, nous avons atteint un point vraiment sympa parce que nous avons une sorte d' indépendance entre nos différents indices.
On y va. Ainsi, nous pouvons voir que les milliers de personnes travaillent aussi. Nous avons cette indépendance entre nos différents fils parce qu'on peut, ce n'est même pas, je veux dire,
cela ferait partie de notre fil conducteur. C' est juste mettre des valeurs dans la file d'attente. Et chaque fois que quelque chose est mis en place, nous avons ici nos différents travailleurs qui sont prêts et disponibles pour commencer à en consommer.
8. Créer un travailleur Postgres: Bon, alors maintenant, allons de l'avant et travaillons sur notre ouvrier d'insertion de base de données. Je vais donc utiliser ma base de données Postgres locale. J' utilise le groupe de données ici, mais bien sûr, vous pouvez utiliser n'importe quel environnement de codage, vous savez, vous appréciez le plus ou codage de l'IDE. Oui, si vous n'êtes pas super frais sur la façon de créer votre base de données Postgres, assurez-vous d'aller de l'avant et de consulter le cours SQL. Mais sinon, oui, il suffit de faire tourner un serveur Postgres local. Et puis je vais juste utiliser la base de données Postgres par défaut ici aussi. Et nous allons juste créer une table dans notre base de données Postgres vont juste insérer ces valeurs dans. Donc je vais dire créer une table, et on appellera ça prix. Et nous allons avoir une colonne d'identification qui va être céréale et nous allons juste être notre clé primaire. Et puis nous allons aussi avoir le symbole, qui va être un, juste b, le texte. Et puis nous allons avoir le prix, qui va être un nombre à virgule flottante. Et puis nous allons aussi avoir le temps, ou nous appellerons cette heure d'insertion. souhaits vont juste être un, eh bien, nous allons juste que ce soit un horodatage. Très bien, donc c'est une table de base de données assez simple que nous avons ici va juste être une table individuelle ici avec l'individu ou être une seule table avec les prix ici, nous allons avoir notre colonne ID, qui va juste être en série comme clé primaire. Et puis juste un symbole ainsi que le prix et le temps. Ou peut-être au lieu d'insérer le temps, nous aurons juste extrait le temps. Donc, le temps où nous l'avons obtenu sur le site. D' accord, alors allons-y et lançons ça. Et on y va. En revenant dans
notre répertoire de threads ici, il a créé un nouveau travailleur, qui va être notre travailleur Postgres. D'accord ? Et là, nous allons avoir deux choses. Je vais juste être notre planificateur maître Postgres, qui va être une instance du thread de thread comme nous l'avions auparavant. Tout comme nous l'avons fait pour le travailleur des prix de Yahoo Finance. Et nous allons excepter les arguments de mots-clés ainsi qu'une file d'attente d'entrée. Et puis nous allons juste initialiser les parents qui transmettent des arguments de mots-clés. Définissez la file d'attente d'entrée pour être la file d'attente d'entrée que nous prenons à partir de l'initialisation. Et puis remplacez la méthode run. Comme on l'a fait pour Yahoo Finance. Et nous dirons ici, encore une fois, nous allons regarder notre file d'attente d'entrée. Et on va juste attendre que j'obtienne la prochaine valeur. Et sans valeur est fait, et nous allons sortir de notre boucle. Bon, donc ça va être l'essence de notre organisateur principal Chris, exactement ce qu'on a fait ici pour Yahoo Finance. Et bien sûr, pour ne pas oublier, nous voulons nous assurer que nous démarrons le thread T2 une fois que nous initialisons ou créons une instance de notre classe. Bon, donc maintenant nous devons faire l'autre chose, qui va juste traiter notre vrai travailleur Postgres, qui va être responsable de l'insertion des données dans notre base de données ici. Et celui-ci dans la méthode d'initialisation. Cela va prendre le symbole ainsi que le prix comme entrée, et peut-être aussi le temps extrait. Il va juste prendre toutes ces valeurs en entrée. Et nous pouvons nettoyer cela dans un peu et faire, que ce soit
une sorte de dictionnaire comme une entrée ou quelque chose où vous pouvez obtenir les valeurs de. Phrenologue, laisse ça tel quel. Donc nous allons avoir notre symbole B, le symbole d'entrée. Nous allons avoir notre prix,
le prix des intrants, vont avoir. L' extrait du temps. Si vous extrayez un temps ici, d'accord ? Et maintenant, nous avons essentiellement besoin de la méthode qui va être insérée dans la base de données. Et ça va faire notre insertion. Et dans notre insertion ici, nous devons essentiellement, tout d'abord, nous devons créer la requête insert. Et puis ce que nous devons faire, c'est que nous devons effectuer l'insertion. Donc, nous allons avoir la requête Create, insert soit une méthode distincte. Je vais juste créer la requête pour nous afin que nous puissions récupérer ça. Et puis nous allons effectuer l'insertion. Donc, pour créer la requête, nous allons faire est, nous allons juste le faire en utilisant SQL brut ici. Nous allons dire insérer dans les prix, les valeurs. Et puis nous allons, eh bien, il y a différentes façons de le faire. L' un d'eux est que nous pouvons utiliser le formatage e, f ici pour dire, eh bien, il est également définir ici l'intérêt de l'ordre de colonne pour être sûr, prix et temps extrait. Assurez-vous que cela correspond à notre syntaxe. Alors mettez ceci sur une nouvelle ligne juste pour le rendre plus clair. Donc encore une fois, la première façon de le faire est d'utiliser les chaînes f. Comme ça. Juste une sorte de formatage dans les valeurs directement. Comme ça. C' est bon. Parce qu'on fait ça en interne. Et il n'y a pas d'entrée extérieure comme ça, mais ce n'est pas le meilleur. Il y a en fait une meilleure façon de le faire, c'
est-à-dire que la mise en forme du texte soit faite pour nous. Et nous avons juste un peu fournir comme ici va être le symbole qui fournira plus tard. Voilà le prix, et voici le temps extrait. Et puis nous n'avons pas besoin d'avoir la chaîne f ici. Et oui, c'est fondamentalement la requête SQL qui est, vous savez, que nous devons avoir. Ce n'est pas grand chose, mais c'est bon. Et puis nous allons juste tourner cette requête. Donc encore une fois, la première chose que nous allons faire ici est que nous
allons avoir une requête d'insertion juste être créée pour nous. Et maintenant, nous devons réellement effectuer l'insertion de la base de données dans l'insertion de la base de données, nous devons mettre en place une connexion à la base de données. Et pour ce faire, nous allons utiliser une bibliothèque appelée alchimie SQL, qui va juste nous aider beaucoup. Ce qui va juste nous aider beaucoup comme la configuration de la connexion à la base de données, l'exécution de ces commandes SQL. Et c'est vraiment comme une bibliothèque générale que nous pouvons utiliser pour simplement se connecter à des bases de données. Mais je vais te montrer comme l'essentiel juste dans une seconde. Mais la première chose que nous devons faire est de l'installer. Donc, nous allons pip installer l'alchimie SQL comme ceci. Et puis dans une seconde, puis nous allons aussi pip installer des tartes P. Et j'espère vraiment que je suis colonne vertébrale est correctement. Mais sinon, je le regarderai dans une seconde. Pie scopy binaire. Il y a une faute de frappe. Alors essayons ça. Et c'est grand. Il est là. Donc c'est pip install pi, psi. Avoir toujours moins profond se souvenir de la prononciation de celui-ci, qui est, je ne peux jamais l'écrire. Psi flic G au binaire. Et cela va nous permettre de mettre en place les connexions Postgres. Nous allons donc installer l'alchimie SQL. Nous n'avons même pas besoin d'importer du psycopg2. Nous allons installer la version binaire parce que c'est parfois si vous n'avez pas de cellule la version binaire, ils sont comme des problèmes avec l'installation. Donc juste toujours installé une version binaire, mais cela va essentiellement nous fournir le pilote que SQLAlchemy peut utiliser pour réellement se connecter à la base de données. Alors oui, comment pouvons-nous configurer cette connexion à la base de données tout en faisant ça ? Donc nous pouvons déjà voir ici que je l'ai déjà importé. Mais nous allons utiliser cette méthode de création de moteur. Et nous allons créer un moteur. Et le moteur va nous permettre d'interagir avec notre base de données. Donc, d'abord, nous devons obtenir tous les paramètres de notre base de données. Nous allons juste être notre nom d'utilisateur Postgres. Et une bonne façon de le faire est de définir ceci comme une variable d'environnement. Postgres. Utilisateur. Ensuite, nous allons obtenir le mot de passe Postgres, dont nous avons également besoin le mot de passe Postgres. Et puis nous allons également avoir besoin de l'hôte ou de l'URL ou où qu'il se trouve. Donc ça va être l'hôte Postgres. Ensuite, nous allons également avoir besoin de la base de données à laquelle nous devons nous connecter sur le serveur Postgres. Ce sont donc les détails de connexion dont nous avons besoin. Et à partir de cela, nous pouvons alors créer une chaîne de connexion qui nous permettra de nous connecter à la base de données. Donc, l'autre chose que j'ai fait ici est que j'ai utilisé le paquet OS, ce qui est vraiment important pour moi juste parce que c'est vraiment sympa. Mais cela me permet juste d'accéder à des choses de notre système d'exploitation spécifiquement ici en allant dans l'environnement point et me permet d'accéder à une variable d'environnement que je peux obtenir. Par exemple, ici, je vais utiliser le point getMethod. Maintenant, si vous ne l'avez pas vu auparavant avec la méthode dot get, c'est si nous créons comme un dictionnaire par exemple, et nous créons juste une variable ici. Si vous faites x point obtenir, malheureusement signifie, Renommons ce x-dot à nouveau. A va obtenir la valeur de ce dictionnaire. Par exemple, si vous faites x-dot Gatsby, qui n'est pas inclus dans le dictionnaire, c'est juste un peu nous en donner aucun. Donc, de cette façon, plutôt que de faire cela, ce qui peut échouer si nous accédons aux valeurs qui sont incluses, la getMethod nous donne soit la valeur renverse none afin qu'elle n'échoue pas. Et puis ce que nous pouvons faire est que nous pouvons utiliser un ou ici, ce
qui se passe est, par exemple, si vous faites en stock obtenir B ou puis nous pouvons fournir comme une valeur par défaut que nous voulons utiliser. A doit être une chaîne et un entier, un entier ou autre. Donc, nous pouvons voir si la valeur n'existe pas, nous obtenons la valeur par défaut. Et si elle existe, alors nous obtenons la valeur de la getMethod ici. Donc, nous allons dire obtenir notre utilisateur Postgres, ou il va juste être vide. Ou ça va être vide. Ou c'est juste pointer vers votre hôte local, ou ce sera Postgres. Maintenant, si vous avez postgres en cours d'exécution sur un Mac et que vous l'avez installé,
il est très probable que votre Postgres local n'ait pas de nom d'utilisateur ou de mot de passe. Mais si vous l'exécutez sous Windows, il est très probable que vous ayez un nom d'utilisateur et un mot de passe. Le nom d'utilisateur sera probablement Postgres, mais le mot de passe sera celui que vous définissez votre installation. Alors rappelez-vous que si vous êtes sur Windows, cela va très probablement être soudain ou Alice va se plaindre qu'il
peut se connecter parce que le mot de passe est nul ou qu'il n'a pas réussi à s'authentifier ou quoi que ce soit. Mais sur un Mac, vous n'aurez pas besoin de définir
un nom d' utilisateur et un mot de passe car vous ne l'avez probablement pas défini à moins que vous ne l'ayez explicitement défini pour votre base de données. Encore une fois, ce que nous faisons ici, c'est que nous essayons soit d' obtenir ces valeurs
à partir de nos variables d'environnement, soit si elles ne sont pas disponibles, nous sélectionnons des valeurs par défaut. Et c'est vraiment sympa parce que nous pouvons alors mettre en place différents environnements, variables d'
environnement pour différents environnements. Par exemple, vous pouvez disposer d'un environnement de test, environnement de
production ou d'un environnement de test local. Si vous ne définissez rien, nous prenons simplement nos environnements de test locaux. Sinon, il faudra toutes les variables que nous définissons. Donc maintenant que nous avons une variable d'environnement dur ici, nous pouvons créer notre moteur qui va nous permettre de nous connecter à une base de données. Nous allons utiliser la méthode du moteur de caisse que nous avons obtenu de SQLAlchemy. Et nous allons juste utiliser des cordes f pour cela. Donc, la première partie, il va juste indiquer qu'il s'agit d'une connexion Postgres. Nous allons faire PostGressQL, barre oblique point-virgule. Et puis nous allons avoir notre utilisateur o. nous allons, nous allons réutiliser ou point-virgule, désolé, deux-points, le passe à l'adresse de l'hôte, comment appelent-ils ça ? Oui, Apigee. L' adresse de l'hôte ou l'adresse IP ou autre, barre oblique, la base de données. C' est donc notre chaîne de connexion ici, nom d'utilisateur, mot de passe, hôte, adresse et la base de données à laquelle nous nous connectons. Bon, maintenant nous avons notre configuration de moteur ici. Nous avons notre requête SQL que nous avons créée ici. La bonne chose à propos du moteur est qu'il
nous fournit un moyen de créer des connexions à la base de données. Mais jusqu'à ce que nous initialisions réellement une connexion à la base de données, aucune
connexion n' est créée. C' est juste, eh bien, c'est fondamentalement juste une classe qui nous
permet de créer cette connexion une fois que nous lui avons explicitement dit de le faire. Alors maintenant, allons de l'avant et exécutons cette requête. On va dire largeur. Et puis en utilisant notre moteur, nous allons nous connecter. Maintenant, il existe différentes méthodes que nous pouvons utiliser ici. L' un d'eux est dot connect, ce qui crée juste une connexion. Nous pouvons également ne pas commencer, ce qui crée une connexion et commence une transaction. Mais nous n'avons pas vraiment besoin d'utiliser les transactions ici. Donc, nous allons juste créer une connexion. Et nous allons avoir ceci dans notre variable de contrôle ici. Et vous remarquerez que tous se souviennent de la syntaxe de aussi comme
ouvrir des fichiers à partir d'un nom de fichier ouvert et puis comme le lire comme un tout dans un fichier, c'est exactement la même syntaxe que nous avons ici où nous ouvrons un fichier, alors nous pouvons faire quelque chose avec un fichier. Et une fois que nous sortons de cette déclaration de largeur, le fichier est également proche pour nous. Donc, nous avons ce gestionnaire de contexte ici, qui est vraiment sympa parce que nous créons la connexion avec elle. Nous pouvons accéder à la connexion en utilisant cette variable de colonne lorsque je l'appelle. Et une fois que nous sortons de ce bloc de largeur, la connexion est automatiquement fermée pour nous, donc nous n'avons même pas besoin de nous en soucier. Donc maintenant, nous pouvons juste utiliser notre connexion. Et avec notre instance de connexion ici, nous pouvons avoir cette méthode not execute, qui va nous permettre d'exécuter cette instruction SQL ici. Maintenant, il y a une autre chose que nous devons faire, qui est que nous devons fournir cette entrée, puisque nous n'avons pas fourni ici en tant que chaînes f. Nous devons donc le fournir quand nous faisons l'insertion. Maintenant, pour fournir le formatage de cette syntaxe, nous avons réellement besoin d'importer
alun, une classe spéciale qui nous permettra de le faire à partir de SQLAlchemy dot SQL. Nous allons importer du texte. Et puis nous allons envelopper ça dans le texte ici. Et ensuite, nous allons fournir notre contribution ici. Donc nous allons avoir notre symbole, qui est ce symbole deux-points, ou symbole, va être le symbole ici. Le prix va être le prix. Et l'extrait une fois. Ce sera le temps extrait ici. Ok, alors allons les repenser une fois de plus. Nous avons donc notre travailleur Postgres, qui prend le symbole, le prix ainsi que le temps extrait comme variables d'entrée. Et puis il crée également une, une instance pour
une connexion de base de données avec l'adresse de connexion postgres. Et puis nous allons appeler, est que nous allons appeler insérer deux bases de données. Et il va créer la requête SQL pour nous. Ensuite, nous allons nous connecter à la base de données. Nous allons donc créer une connexion à la base de données. Et avec cette connexion, nous allons exécuter l'instruction SQL que nous avons créée ici. Nous allons utiliser cette mise en forme de texte ici parce que nous avons ce format spécial qui nous permet fondamentalement une certaine protection contre la taxe d'injection. Donc juste que le formatage est correct. Et puis nous pouvons réellement fournir le formatage ici comme juste une seconde variable d'entrée et un dictionnaire très simple. Et puis il va remplir les valeurs pour nous. Et puis une fois que nous sortons de cette instruction width, La connexion va également être automatiquement fermée pour nous parce que nous utilisons ceci avec déclaration ici. Donc un très pratique, accord, alors revenons à notre planificateur principal. Et ce que nous devons faire ici, c'est une fois que nous obtenons une valeur de notre file d'attente d'entrée, ici, nous allons alors créer une instance de notre travailleur Postgres, veillant à fournir
le symbole, le prix, ainsi que l'extrait un temps. Et donc, nous allons l'obtenir de, eh bien,
et supposons que c'est ce que nous allons obtenir avec notre valeur d'entrée ici. Donc, notre valeur d'entrée ici qui va être une liste qui ressemble à ceci, ou ce sera un tuple qui ressemble à ceci. Quoi qu'il en soit, parce que nous avons un contrôle total sur cela, nous allons supposer que c'est la façon dont nous avons obtenu nos données. Bien sûr, vous savez, nous pouvons rendre cela plus général et avoir juste ce soit comme un dictionnaire. Et puis nous pourrions dire symbole est égal à la valve, nouveau symbole et faire la même chose pour le prix égal à Val point obtenir, Prius et ainsi de suite. Le rend un peu moins sujet aux erreurs. Mais, tu sais, ce n'est pas le but de ça en ce moment. On est juste, tu sais, on veut juste faire fonctionner ça. Donc, nous allons juste nous assurer pour l'instant que c'est comme ça que ça va marcher. Et puis une fois que nous aurons notre instance de travailleur de cas pros ici, nous allons appeler insert dans la base de données. Bon, donc ça crée notre ouvrier Postgres. Maintenant, nous allons continuer cela dans la leçon suivante parce que nous
devons également fournir la file d'attente d'entrée ici. Nous devons envoyer ces valeurs là-dedans. Et aussi, nous devons inclure cela dans notre fonction principale ici, parce que cela devient déjà assez long. Allons de l'avant et arrêtons ici pour l'instant et continuons cela dans la leçon suivante.
9. Intégrer le travail Postgres: Bon, maintenant que nous avons installé notre portier Postgres,
allons de l'avant et continuons avec ça. Intégrez ceci dans notre fonction principale, et apportez d'autres changements pour vous assurer que tout fonctionne correctement. Donc, tout d'abord, dans l'ordre, fonction principale, nous allons importer le planificateur maître Postgres. Et nous allons faire une chose similaire comme nous l'avons fait pour Yahoo Finance, ici. Ceci et ceci, c'est au lieu de la finance, ce sera nos diplômés de poste. Et changeons l'entrée en cubes et une seconde. Et juste mettre à jour les noms ici. On y va. Et NAM, travailleur post-diplômé, comme ceci et la file d'attente d'entrée. Donc maintenant j'ai besoin d'un nouveau Q. Et ça va être une queue de Postgres VIP comme ça. Très bien, donc nous avons des threads de programmateur Postgres ici, nombre de travailleurs de podcasts, supposons à deux. Pour l'instant, voyons comment les choses se passent. Postgres scheduler, qui va être une instance pour Postgres master scheduler, qui va avoir cette file d'attente d'entrée ici. Et vous gardez une trace de ces menaces. Bon, alors maintenant que nous avons ce Postgres Q, nous avons vraiment besoin d'y mettre des valeurs. Et donc nous allons avoir ce soit une file d'attente de sortie. Top, nous allons fournir à un planificateur de prix Yahoo Finance. Maintenant, il y a deux façons d'y arriver. Le premier est bien sûr que nous pouvons explicitement en faire un argument d'entrée. Ou nous pouvons simplement utiliser nos arguments de mots-clés ici. Et puis nous allons dire, ok, donc nous avons sur notre OOP de sortie, ou sortie Q, est-ce que ça va être ? Et puis à partir de nos arguments de mots-clés, nous allons obtenir la sortie Q. Et si cela n'existe pas, ce n'est pas le cas. Sinon. Ouais, on va avoir des valeurs d'ici. Bon, alors pendant la méthode de course, nous avons le prix ici. Et puis nous pouvons dire, si la sortie Q n'est
pas, pas, alors dans notre Q de sortie, nous allons mettre ce prix. De même. Une fois que nous avons terminé ici, allons de l'avant et assurez-vous que nous envoyons également fait à nos marqueurs en aval. Bon, alors qu'est-ce qu'on vient de faire ? Eh bien, nous avons ajouté une file d'attente de sortie. Et la raison pour laquelle nous avons besoin d'un Q de sortie est parce que nous avons maintenant un processus en trois étapes. La première étape consiste à obtenir tous les symboles, ce que nous faisons avec notre collaborateur wiki, ce qui n'est pas un thread. C' est juste, eh bien, ça fait partie du terme principal, mais c'est juste un travailleur qui obtient tous les symboles qui le place dans le symbole Q.
Le symbole Q est alors lu par le planificateur de prix Yahoo Finance, le planificateur principal ici. Et chaque fois qu'il obtient la valeur, il va le traiter et obtenir le prix. Maintenant, au lieu d'imprimer le prix, il va l'envoyer à la sortie Q ici. Et la sortie Q est ce que notre planificateur maître Postgres ici va consommer comme sa file d'attente d'entrée, comme nous pouvons le voir ici. Et jetons un coup d'oeil à ça. Et une fois que nous avons terminé, une fois que
nous sortons, nous voulons nous assurer que nous avons également mis dans la sortie Q et nous avons terminé. Alors ce que les travailleurs en aval sont aussi, vous savez, faire passer ce message fait à leur transmettre. Maintenant, une chose importante à connaître est le format que nous attendons ici. Ici, comme nous nous attendons
le symbole, le prix, ainsi que l'extrait au temps. Donc, nous allons réellement définir ces valeurs pour être les valeurs de sortie. Donc, vous devez fournir le symbole ici, qui va être la valeur que nous obtenons d'ici, le prix, ainsi que le temps extrait, qui convertissons simplement cela en un entier. Et c'est ce que nous allons mettre dans votre Q. Depuis encore une fois, notre travailleur Postgres attend le symbole, puis le prix, puis le symbole temporel extrait, car ils obtiennent cela à partir de la file d'attente d'entrée, qui a le symbole Q. Prix. Et puis le temps extrait juste ici. Et ces valeurs que nous allons mettre dans notre Q. de sortie ,
puis nous allons les lire ici comme notre file d'attente d'entrée dans notre travailleur Postgres. D' accord, donc, ouais, et ensuite on va envoyer la valeur w1, qu'on peut obtenir ici. D' accord, alors allons-y et, allons de l'avant et testons ça. Voyez comment les choses tournent s'il y a quelque chose que nous avons manqué. Vous avez une sortie d'argument de mot clé inattendue Q. OK ? Donc, en fait, dans ce cas, nous devrions explicitement le définir parce que nous transmettons des arguments de sortie similaires. Et donc cela nous donne où nous passons nos arguments de mots-clés. Et c'est en gros dire, oh, eh bien, ok. La classe de threading qui utilise ces arguments de mot-clé, ne sait pas quoi, comment gérer les files d'attente de sortie. Donc, en fait, va le définir explicitement pour que nous ne le transmettions pas parce que cela provoque des erreurs en aval. Comme ça. Allons-y et courons ça une fois de plus. Voyez comment les choses se passent maintenant. Ok, on dirait que les choses tournent et que les valeurs sont transmises. Bud, nous avons des problèmes à insérer les données dans notre base de données. D' accord ? Et le problème principal semble être ici avec notre horodatage. Et ce cas, c'est vraiment juste se plaindre que nous fournissons un entier ici, mais il s'attend à un horodatage. Allons-y et incluons un casting ici. Mettons ceci sur une nouvelle ligne juste pour rendre le formatage plus facile. Nous allons donc lancer cette valeur comme un horodatage. On va faire des listes de casting ici. Allons essayer encore une fois. J' ai toujours des problèmes. Et voyons quelle valeur on passe ici. Bien sûr, nous utilisons le. Commençons donc par envoyer la valeur temporelle. Oups, nous voulons envoyer fondamentalement comme une instance datetime que nous pouvons insérer. Donc comme ça. Et je ne m'attends plus à ce que nous ayons besoin de ça. Et nous allons juste aller de l'avant et assurez-vous de lancer ceci comme une chaîne afin que nous obtenions le format de chaîne. Pour que la valeur que nous allons obtenir ici soit comme ça, quelque chose comme ça, peu importe. Je fais juste un temps, comme un format comme ça. Bon, donc nous allons l'obtenir en utilisant la classe datetime ici. Donc, nous allons passer un objet datetime, qui va être UTC. Maintenant, quand vous utilisez UTC maintenant au lieu de maintenant, juste pour que tout soit standardisé et nous avons toujours besoin de la bibliothèque de temps
pour, au sommeil ici à la fin. Bon, allons-y et essayons encore une fois. Il semble être en cours d'exécution et nous n'aurions pas de sortie d'impression, mais allons de l'avant et vérifions notre base de données. Tirer une table ici. Oh, on y va. Donc, nos valeurs sont insérées pour nous comme nous pouvons le voir, ce qui est vraiment génial. Donc c'est exactement ce que nous attendons. Et oui, donc fondamentalement
récapitons rapidement ce qui se passe en ce moment parce que nous avons beaucoup de pièces en mouvement différentes. Donc la première chose que nous avons notre fil principal ici. Dans notre thread principal, où alors créer un symbole Q ainsi qu'un Postgres q. Ce sont des indices où nous allons transmettre
les symboles que nous obtenons de notre scrubber wiki. Donc juste en regardant la page wiki ici, cela passe par tous les symboles ici. Tous les symboles ici, et il les transmet dans ce symbole de sortie Q ici. Et puis notre planificateur de prix Yahoo Finance, dont nous avons actuellement quatre instances, va lire à partir de cette file d'attente. Et puis il va obtenir le prix ou il va essayer de le faire, et il va le transmettre à la pointe Q en aval à faire. Et il va le transmettre au Q en aval, qui sera notre Postgres Q ici. Et cela va prendre ces valeurs. Il va lire à partir du Postgres Q, qui est la sortie Q ici. Et notre travailleur Postgres va juste continuer à lire de cette file d'attente. Et chaque fois qu'il obtient une valeur, c'est, oui, je vais l'insérer dans la base de données et nous allons nous obtenir la valeur w1. Ensuite, il va sortir de la boucle ici. Et nous nous assurons de simplement, si nous obtenons la valeur w1 dans notre entrée ici, nous nous assurons de transmettre cela à la sortie Q, qui est que postgres va lire à partir de Sloan. Oui, c'est un peu ce qu'on se passe. Voyons combien d'enregistrements nous avons dans notre base de données maintenant. A 180. Donc on s'attend. 550. Et encore une fois, c'est plutôt lent, juste parce que nous sommes que nous avons ce truc du sommeil qui se passe ici pour limiter la vitesse à laquelle vont. Parce que, bien sûr, cela pourrait fonctionner beaucoup plus vite. Donc, pour juste s'assurer que cela se termine correctement, plutôt que d'obtenir tous les symboles. Je vais juste avoir un symbole ou pas. Oui, on aura un compteur de symboles. Et chaque fois qu'on insère un symbole, on va l'augmenter d'un. Et puis disons juste pour s'assurer que cela fonctionne correctement. Si, oh, sur, si nous avons au moins cinq symboles, nous allons sortir de ça juste pour nous assurer que nous n'avons pas à
attendre jusqu'à ce que nous atteignions comme 550 ici, juste pour voir si ça fonctionne correctement. Donc nous allons arrêter de ça, relancer ça. Et maintenant ça devrait aller beaucoup plus vite. Nous devrions aller cinq symboles qui devraient être insérés dans la base de données. Et puis tout devrait sortir, ce qu'il fait. Super. Donc, c'est important pour nous parce que si ça ne sortait pas, cela signifie
que nos fils sont suspendus quelque part, qu'il y a toujours un fil actif quelque part. Et nous pouvons voir que c'est ce que nous aurions. Si on n'a pas fait ça. Alors nos travailleurs de Postgres n'auraient jamais été informés, vous savez, terminés et ils continueraient tout simplement. En fait, on dirait que nous ne nous joignons pas, qui est ce qu'on voit ici. Mais, vous savez, nous ne sortons pas parce que nos Postgres, les travailleurs sont coincés dans cette boucle essentiellement bloqués par ça. Ils attendent d'obtenir la valeur suivante, mais la file d'attente est vide et rien n'est mis dans la file d'attente. Donc juste coincé ici pour toujours, donc ça ne va pas s'arrêter. C' est pourquoi il est important que nous transmettions ces valeurs pour nous assurer que les repères en aval sont également conscients que, accord, il est temps d'arrêter. Donc, en sortant de cela, il y a encore une chose que nous pouvons faire pour aider à prévenir cela. Donc, en fait, laissons cela commenté pour l'instant et allons dans notre travailleur Postgres. Et ici, nous allons ajouter un délai d'attente. Et mettons ça à 10 secondes. Et nous allons dire, d'accord, si nous n'avons pas de valeur dans 10 secondes, alors nous voulons sortir. Donc, nous allons ajouter une instruction try and except ici
et obtenir l'exception vide spéciale, nous pouvons obtenir de Q. Importer la file d'attente vide est à nouveau une bibliothèque Python par défaut. Donc, nous pouvons juste importer d'ici. Et le multi-traitement Q, qui est ce que nous avons importé ici,
en fait, implémente directement la classe de file d'attente à partir de la bibliothèque Python de file d'attente standard. Donc, à partir d'ici, nous pouvons obtenir l'exception vide. Donc, si nous attrapons spécifiquement l'exception vide, alors nous voulons juste imprimer Q ou timeout brisé et Postgres, l'ordonnanceur s'arrête. Et puis aussi ici aussi, nous voulons sortir. Donc, dans ce cas, nous ne sommes pas, nous n'envoyons pas le signal fait à un travailleur Postgres. Et donc ça va être un peu accroché. Et mais il va y avoir un délai d'attente ici. Et nous allons en fait voir dans un petit peu que travailleurs de Postgres vont s'arrêter de toute façon parce qu' il n'y a rien dans la file d'attente et qu'il a atteint les délais d'attente. Donc on peut voir ici le premier segment d'arrêt, stop. On y va. C' est pour ça que c'est sympa parce que, tu sais, il te protège contre l'attente éternelle. Mais bien sûr, besoin d'être conscient parce que si vous avez eu un temps d'arrêt dans le délai d'attente
n'est pas assez grand pour que les valeurs entrent dans le haut. Vous êtes en aval, les travailleurs vont vraiment
arrêter de fumer avant qu'ils aient jamais eu la chance de travailler. Ou s'il y a une interruption entre les deux, alors, vous savez, vos travailleurs en aval vont cesser de fumer pendant que des choses se passent encore. Donc, vous devez être un peu prudent à ce sujet. Vous savez que vous ne définissez pas votre temps pour être trop court parce que, bien sûr, c'est parce que cela peut causer des problèmes. Et donc, vous savez, vous voulez vous assurer que vous finissez idéalement toujours par envoyer une sorte de commande de sortie comme. Voyons votre QRS maintenant. Ok, il est temps de s'arrêter ici. Et bien sûr, nous avons le délai ici et nous pouvons faire la même chose pour notre Yahoo Finance ira ici. Nous allons dire, essayez d'obtenir une valeur. Nous obtenons l'exception vide. On va imprimer Yahoo. Planificateur. La file d'attente est vide. Et puis on va dire qu'on s'arrête, on va sortir. Et nous allons dire pour Q et port vide. Ça, je vais juste réorganiser les importations ici un peu. Que toutes les bibliothèques par défaut sont en haut ici. Et toutes les bibliothèques installées sont en bas. D'habitude. On y va. Fournit juste une structure un peu plus facile que nous savons que ce sont tous les paramètres par défaut et ceux-ci que nous avons dû installer. Ok, Donc et tout ce que nous avons ajouté sortant n'a pas vraiment défini de délai d'attente ici. Donc, nous sommes également en train de définir un délai d'attente ici juste au cas où. Mais bien sûr, soyez prudent à ce sujet parce que vous pouvez faire sortir vos travailleurs pendant qu'ils devraient encore travailler parce qu'il y a une sorte de retard en amont. Et nous n'avons pas besoin d'arguments de mots-clés ici. Donc on peut juste les sortir pour imprimer la déclaration ici non plus. Ok, ouais, donc maintenant nous avons nos employés à l'un d'eux, sorte d'obtenir les symboles d'ici. Pour chaque symbole que nous obtenons, nous le transmettons pour obtenir les données de Yahoo Finance. Et pour chaque prix que nous obtenons, nous mettons cela dans un q en aval, qui sont les travailleurs de Postgres vont alors consommer à partir de. Maintenant, il ne reste plus que quelques petites choses à faire, qui va juste faire la jointure à la fin ici. Donc nous allons passer en revue Postgres, menaces de
planificateur, et juste appeler les jointures à la fin ici. Et je vais en fait changer la logique de notre QS de sortie ici peu, parce qu'il est possible que, vous savez, en ce
moment, nous supposons que nous avons un Q de sortie, mais peut-être que nous voulons avoir plus d'un Q. Donc, pour s'adapter à cela, je vais lire ceci dans une variable temporaire. Je vais dire que si notre Q temporaire n'est pas beaucoup de liste, alors je veux juste que ce soit une liste. Donc maintenant, notre QS de sortie va être une liste qui peut être une, ils peuvent être plusieurs. Et puis nous devons bien sûr, changer un peu ça. Et parce qu'on n'en aura plus ici. Donc, ce que nous pouvons faire est que nous pouvons dire pour la sortie Q dans les files d'attente de sortie. Et puis pour chaque sortie Q, nous allons envoyer sur fait. Et s'il n'y a pas d'éléments ici, alors cela va être vide. Donc, il n'y a pas de files d'attente de sortie, alors cela va être vide. Sinon, tu sais, si on en a un, alors on en aura un. Et si nous en avons plus d'un, alors nous en aurons plus d'un. Et on peut en fait oui. D' accord. Donc oui, alors maintenant nous avons juste rendu ça un peu plus agréable parce que nous pouvons fournir cela comme une liste d'entrées. Et faisons cela aussi, même si nous acceptons seulement la variable spécifique. Mais cela fournit cela comme une entrée, comme une liste. On peut avoir un q en aval ? Allons de l'avant et exécutons ceci une fois de plus pour nous assurer que cela fonctionne. Mais de cette façon, nous avons maintenant un peu plus de flexibilité parce qu'elle a
peut-être oublié de le changer ici. Oh, on y va. Quatre, sortie Q et sortie QS. On y va. Bon, donc maintenant nous avons un peu plus de flexibilité parce que peut-être nous ne voulons pas simplement enregistrer cela dans une base de données, mais peut-être que nous voulons peut-être enregistrer cela dans plusieurs bases de données. Donc, ce que nous pouvons faire est que nous pouvons avoir notre principal travailleur Yahoo Finance ici, plutôt que d'avoir un seul Q. Il peut avoir plusieurs files d'attente de sortie et différents travailleurs en aval. On peut dire qu'on a un travailleur de Postgres. Nous pouvons aussi avoir comme j'ai lu un travailleur américain ou un travailleur
MySQL ou n'importe quelle autre base de données que vous avez. Chacun d'entre eux peut être consommé à partir des différents indices que nous fournissons ici. Et notre collaborateur Yahoo Finance écrira simplement sur chaque Q. Donc, chaque Q. de sortie unique que
nous avons, nous allons écrire ces valeurs aussi. Et puis les travailleurs en aval peuvent, vous savez, utiliser toutes ces choses et nous obtenons essentiellement les prix, mais nous pouvons les réutiliser en quelque sorte
les mettre dans les différents indices pour que les différents travailleurs puissent en consommer. Et donc cela nous donne plus de flexibilité parce que, vous savez, ce ne sera pas toujours un dans, un sur. Parfois, il n'y aura pas de sortie. Parfois, il va y avoir plusieurs sorties. Et donc, cela nous donne juste un peu plus de flexibilité dans ce sens.
10. Introduction du fichier Yaml: Bon, alors maintenant que nous avons ce programme de travail mis en œuvre, allons-y et nettoyons-le un peu. Rendre un peu plus agréable d'avoir une vue d'ensemble
ainsi que de pouvoir l'étendre plus tard si nous le voulons, sans vraiment toujours avoir à ajouter de nouveaux extraits de code ou copier coller ou modifier la logique là-dedans. Donc à la place ce que nous allons faire, et nous allons en fait définir cela dans une sorte de fichier où nous pouvons spécifiquement dire que ce sont les indices que nous avons, soit les travailleurs que nous avons. Et cela définira notre programme ici. Et donc ce qu'on va faire, c'est écrire un fichier YAML. Et c'est ce que nous allons aborder dans cette leçon, écrire le fichier ainsi que comment nous pouvons le lire et vraiment ce que cela signifie pour nous. Donc, pour ce faire, nous allons commencer et créer un nouveau répertoire ici. Et je vais appeler ça Pipelines. Tu peux l'appeler comme tu veux. Je vais appeler des pipelines parce que ce que nous avons ici en quelque sorte dans le pipeline, nous commençons par décrire les données brutes du site Wikipédia, les
transmettre, être extraites du signe Yahoo, puis en les passant pour être téléchargé dans Postgres. Donc ça va être un pipe-line pour nous ici. Et donc ici, je vais créer un nouveau fichier. Et ça va être notre wiki, Yahoo, ferraille ou pipeline, et l'appeler point YAML. Pourquoi ML ? Maintenant, pour pouvoir lire ce fichier en Python, et nous allons juste faire ce genre de peu à la fois. Nous allons également activer mon environnement virtuel ici. Mais je vais aller PIP et trébucher. Pi YAML. Appuyez sur Entrée ici et laissez cette installation. Et c'est une sorte de maintenant et la bibliothèque dont nous avions besoin pour être en mesure de lire ceci. Et donc en une seconde, quand nous écrivons ce fichier YAML, nous pouvons utiliser la bibliothèque de tartes, qui va alors simplement convertir cela en
une sorte de structure de liste imbriquée ou de dictionnaire pour nous que nous verrons dans une seconde. Donc, la première chose que nous voulons, si nous regardons simplement notre programme principal ici, c'est si nous avons des files d'attente. Nous devons donc définir les indices que nous voulons. Et puis nous avons aussi des travailleurs. C' est un peu comme les essences de ce que nous voulons. Donc je vais définir ici, et je vais juste dire, d'accord, sont les indices que nous voulons. Et je vais juste écrire ça un peu,
puis dans une seconde nous allons le lire et, vous savez, nous pouvons explorer un peu comment ce fichier
YAML se transforme en structure de données Python. Donc ici, je vais juste énumérer les indices. Le premier, je vais lui donner un nom. Et cela va être, si nous revenons à notre fonction principale ici, ce sera le symbole Q. Donc je vais appeler ce symbole Q, appeler comme vous voulez. Et je vais aussi lui donner une description. Encore une fois, ne vous inquiétez pas pour ça maintenant. Je vais récupérer ça dans une seconde. Je veux juste avoir quelque chose ici pour qu'on puisse le regarder. Et ce sera les symboles contenant à supprimer de Yahoo Finance. Et puis nous voulons avoir un autre Q, qui va être notre téléchargement Postgres. Et la description ici va être contient des données qui doivent être téléchargées. Postgres. Et puis nous avons aussi des travailleurs. Et les ouvriers. Le premier ici, si nous regardons ça, va être notre collaborateur wiki ou nous pouvons, ouais, ok, travailleur va bien. Ici, nous pouvons donner une description. Cela supprime la page Wikipédia brute et retire les symboles. Et encore une fois, nous allons en quelque sorte examiner cela itérativement. Mais je voulais avoir le genre de base comme l'emplacement ou on peut trouver cet ouvrier. Donc, il va être dans les travailleurs dot key worker. Et la classe que nous voulons utiliser sera cette classe de travailleur wiki que je vais mettre ici. Et puis nous voulions aussi trouver des files d'attente d'entrée, et cetera, que, que nous allons obtenir dans un peu. Mais laissons-le à ça. Maintenant, nous avons quelque chose à regarder. Et puis allons de l'avant et chargeons ceci et voyons comment ces fichiers YAML se traduisent en quelque chose d'utilisable en Python. Donc, je vais juste lancer Python sur mon terminal ici. Et je vais importer YAML, ce que nous pouvons maintenant faire parce que nous avons déjà installé PMO. Maintenant ce que je vais faire, c'est que je vais dire avec ouvert. Les conduites de tuyaux. Et je vais juste copier ce nom ici parce que je vais probablement l'épeler mal. Et puis nous devrons trouver la faute de frappe. Je vais l'ouvrir en mode lecture. Je vais dire, appelez ça notre dossier. Et encore une fois, passons en revue et nous allons résumer
tout ce qu'on a fait. Nous allons faire un peu d'exploration, mais nous devons d'abord avoir une sorte de base. Et donc nos données YAML vont juste être, et ensuite nous allons utiliser notre bibliothèque YAML. On va faire le chargement en toute sécurité. Et nous allons mettre un ici, notre fichier d'art juste dans lequel nous l'avons lu pour appuyer sur Entrée. Bon, donc on l'a chargé. Alors allons-y et jetons un coup d'oeil à ça. Donc, nous pouvons voir est nos données YAML est en fait, et si nous regardons son type, est un dictionnaire. Donc la première clé que nous avons sont les clés que nous avons. Si nous regardons les clés, est-ce que nous avons deux clés, des indices et des travailleurs, et c'est exactement ce que nous avons ici. La première chose est un q, et la deuxième chose est un travailleur. Et vous pouvez presque maintenant voir ce que nous obtenons en Python, vous pouvez reconnaître la structure ici, non ? Donc, nous avons fondamentalement ce genre de format de dictionnaire
familier où nous avons le nom, puis le point-virgule, et ensuite nous avons les valeurs contenues à l'intérieur. Maintenant ce que nous pouvons voir ici est à l'intérieur des indices, nous avons en fait une liste. Alors allons de l'avant et prenons nos données YAML. Nous allons regarder dans les files d'attente. Donc, ici, nous avons une liste. Et la raison pour laquelle nous obtenons une liste est parce que nous utilisons effectivement ces tirets qui indiquent des éléments de liste. Donc, dans ce cas, nous devons énumérer les éléments ici. Mais si nous regardons à l'intérieur, disons que le premier élément de liste verra à nouveau ici, nous avons un dictionnaire comme nous le faisons ici. Donc, nous pouvons voir que nous avons comme une forme répétée dès le début, nous définissons un type de clés de dictionnaire. Ensuite, à l'intérieur, nous définissons le contenu. Et puis à l'intérieur, dans ce cas, nous utilisons des éléments de liste indiqués par un tiret. Et puis à l'intérieur, nous avons encore un dictionnaire que nous pouvons voir ici. Nous avons le nom, qui est le nom ici, et nous avons la description. Maintenant, quand j'écris ceci, vous avez peut-être pensé, Oh, vous utilisez des mots clés spécifiques pour indiquer toutes ces choses. Je ne sais pas. J' ai juste décidé d'utiliser la description du nom, classe d'
emplacement parce qu'ils sont pratiques et ils sont clairs pour le programmeur quand vous lisez ceci, ils sont très descriptifs et clairs, mais vous savez, vraiment ne s'en fous ce qui utiliserait. Nous pourrions vraiment utiliser n'importe quoi ici parce que, encore une fois, nous avons juste des dictionnaires et des listes d'ici que nous pouvons utiliser. Mais juste pour nous faciliter la vie, que ce
soit quand nous l'écrivions maintenant ou quand nous y reviendrons, quand nous voulons le montrer à d'autres personnes, nous voulons nous assurer que nous utilisons des noms descriptifs pour que, vous savez, c'est gentil de clair ce qui se passe. Donc quelque chose que nous pouvons aussi faire en fait, ce qui peut aider à effacer un peu la syntaxe. Au lieu d'utiliser cette syntaxe ici, nous pouvons réellement utiliser une syntaxe comme celle-ci et le résultat, mais nous allons obtenir va être la même. Alors revenons ici et nous allons recharger nos données. Et puis jetons un coup d'oeil à nos données YAML. Et nous pouvons voir ici les valeurs que nous obtenons ici sont, remarquez que j'ai une faute de frappe et une description ici. Mais nous pouvons voir que les valeurs que nous obtenons ici sont toujours les mêmes, n'est-ce pas ? Rien n'est changé dans le même format est ici. Maintenant, c'est juste une façon différente de le représenter. Donc, si vous voulez, ce genre de le ramène presque exactement à la structure Python que nous avons à laquelle nous sommes habitués en Python, sauf bien sûr que nous utilisons des guillemets puisque nous définissons
réellement un dictionnaire et sinon nous référencerait des noms de variables. Mais une fois que vous vous y habituez, ce format peut en fait être un peu plus propre à lire que celui-ci. C' est pourquoi je vais annuler ces modifications. Et je vais l'avoir comme
avant parce que ça devient un peu plus propre à lire. Mais l'autre moyen est juste de vous montrer, encore une fois, peut-être le traduire en des choses comme, vous savez, en Python afin que vous puissiez mieux comprendre ce qui se passe exactement. Mais nous pouvons voir ici, ok, donc nous avons défini les indices et encore une fois, nous les appelons des indices parce que c'est pratique pour nous, pas parce qu'il y a besoin d'une autre façon. Et nous avons ces travailleurs ici de nouveau parce que c'est pratique pour nous. Donc nous avons notre collaborateur wiki. Et encore une fois, ici ces noms n'ont pas besoin d'être les mêmes. C' est juste, vous savez, peu pratique et descriptif à utiliser, mais on peut appeler ça quelque chose d'autre. Cette année est importante parce que nous allons l'utiliser plus tard, pas maintenant, mais plus tard. Nous l'utiliserons pour charger et initialiser dynamiquement cette classe à partir de cet emplacement. Donc, nous voulons nous assurer que ce chemin d'emplacement et pourrait également l'appeler un chemin basé sur le chemin, ce qui est correct. Et puis ici, nous voulons nous assurer que nous référençons le bon marqueur comme celui-ci afin que nous puissions réellement l'initialiser. Nous avons donc le seul travailleur ici. Je veux aussi mettre des files d'attente d'entrée. Maintenant, dans ce cas, nous n'avons pas de file d'attente d'entrée. Donc je ne vais pas le définir. Mais peut-être que nous voulons passer comme des valeurs d'entrée. Et ceux-ci peuvent être juste une liste d'URL à nettoyer, par exemple. Donc quelque chose que nous pourrions faire est que nous pouvons prendre cette URL ici que nous voulons jeter et plutôt que de la coder en dur dans notre collaborateur wiki, nous pouvons réellement la définir ici. Et puis si nous avons d'autres sites wiki qui suivent la même structure qui nous permettent réellement de réutiliser ou de travailler, ou nous agrandissons ou travailleurs pour être en mesure d'accepter ces différents sites. Nous pouvons mettre plus d'URL ici quand nous arriverons à ce point. Ou, vous savez, si jamais vous avez des données comme ça. Mais pour l'instant, on va rester avec ça, mais, tu sais, rendre ça un peu plus général pour que nous définissions tout ici. Donc nous avons notre premier travailleur. Ensuite, nous allons créer notre deuxième travailleur, qui si nous regardons en arrière notre fonction principale ici, nous avons notre collaborateur Yahoo Finance. Donc ça va être notre employé de Yahoo Finance. La description ici va être tire des données ou tire des données prix pour un symbole boursier spécifique de Yahoo Finance. L' emplacement ici va être des travailleurs point, et je vais juste copier ce nom
ici pour qu'il n'y ait pas de fautes de frappe parce que ça va être frustrant. Et la classe que nous voulons charger ici sera notre jeune planificateur de prix Yahoo Finance, pas les travailleurs des prix qui seront les mêmes que nous utilisons ici. C' est donc ce que nous voulons utiliser. Et ici, nous allons avoir une file d'attente d'entrée aura juste ce soit une entrée singulière q. Et ce sera en fait, nous pouvons juste garder ceci directement comme un dictionnaire à la place. Donc, notre entrée q ici va être, eh bien, la sortie d'ici. Alors allons de l'avant et définissons QS de sortie. Celle-ci, nous allons avoir un pluriel au cas où vous vouliez l'envoyer à plusieurs repères. Mais pour l'instant, nous allons simplement l'envoyer au symbole Q que nous avons défini ici. D' accord ? Et encore une fois, nous faisons juste référence
aux noms ici parce que ce ne sont que des files d'attente générales. Et donc nous pouvons référencer ces différents indices. Ceux-ci sont, nous verrons plus tard comment nous allons les utiliser. Mais oui, cela, avoir ces conventions de nommage, surtout pour le Q un peu nous permet juste de nommer correctement et de référencer tout. Donc, notre entrée q ici va être notre symbole Q. Et notre QS de sortie ici va être juste notre Postgres téléchargement Q. Maintenant, la raison pour laquelle je veux avoir plusieurs QS de sortie est peut-être que je ne veux pas juste envoyer cette information à un emplacement dans un type de travailleur en aval, mais en fait plusieurs. Donc peut-être que je veux que mon travailleur wiki
l'envoie au travailleur Yahoo Finance pour obtenir les données de prix, mais aussi que je veux l'envoyer à un autre travailleur, qui juste stocker directement toutes ces données brutes quelque part et ne fait rien d'autre avec ça. Ou peut-être qu'il fait quelque chose de complètement différent avec elle. Donc, de cette façon, je peux l'envoyer à plusieurs endroits et différents travailleurs en aval peuvent voir qu'ils lisent à partir d'ici. Leur aval peut utiliser cette information de différentes manières. Droit ? Définissons notre dernier travailleur. Si nous revenons à notre fonction principale, ce sera notre animateur Chris hôte. Alors celle-là. Donc, ici, nous allons appeler ceci notre description des travailleurs Postgres. Prenez les données de stock et économisez dans Postgres. L' emplacement va manger. Travailleurs, travailleurs de points postgres. Et la classe que nous allons utiliser va à nouveau être le planificateur principal. Puisque ça va être celui qui va lire dans la file d'attente et tout. Tout comme nous le faisons dans notre fonction principale ici. D' accord ? La file d'attente d'entrée. Il va y avoir postgres téléchargement. Et en fait, nous ne allons même pas définir une file d'attente de sortie parce qu'il y a, vous ne voulez plus envoyer ces données. Très bien, donc ce sont nos définitions de base. Maintenant, nous pouvons mettre à jour ce fichier YAML plus tard ou nous pouvons changer un peu au fur et à mesure que nous allons continuer. Nous remarquons que peut-être vous voulez décrire les choses un peu différemment. Mais pour l'instant, c'est une sorte de description de base d'un programme, bien sûr, heure actuelle, ne fait rien parce que nous devons en faire usage,
ce que nous ferons dans les leçons à venir. Mais allons-y et lisons ceci pour que nous puissions voir ce que nous avons. Et bien sûr, pour s'assurer que ça marche. Donc, en regardant, nous avons les différents indices et travailleurs. Et dans les files d'attente, nous avons deux files d'attente, le symbole Q ainsi que le téléchargement Postgres. Et chez nos travailleurs, nous avons jeté un coup d'oeil à cela. Dans notre travailleur est que nous aurions plusieurs différents et nous avons le travailleur wiki, qui a également des valeurs d'entrée ici, nous pouvons voir qu'ils ont été transférés correctement. Nous avons notre ouvrier Yahoo Finance va référencer le jeune ami est planificateur de prix. Et notre travailleur Postgres, qui va faire référence à l'ordonnanceur maître Postgres. Donc maintenant nous avons un peu ce pipeline complet, définissez-le dans ce fichier YAML. Encore une fois, bien sûr, nous n'en avons pas encore fait usage. C' est ce que nous allons faire dans les prochaines sections. Mais j'espère que vous pouvez voir que si nous pouvons transférer la description générale du fonctionnement d'un programme, au lieu de tout coder ici pour qu'il soit beaucoup plus configurable dans ce fichier YAML. Cela nous donne beaucoup de flexibilité, car une fois que nous créons dynamiquement nos travailleurs et les envoyons à chacune de ces files d'attente. Si nous voulons ajouter une autre base de données d'enregistrement ailleurs. Plus tard, nous disons que tout ce que nous voulons aussi sauver ici en fait seulement avoir à faire est abord que nous devons écrire la classe pour elle comme nous l'avons fait ici qui peut s'en occuper. Mais disons juste que nous voulons enregistrer ceci pour que je ne sais pas, quelque chose comme une base de données Redis. Donc nous allons juste ajouter une autre file d'attente. Et puis nous allons aussi l'envoyer ici. Et puis on peut dire,
oh, j'ai juste remarqué qu'il y a une faute de frappe ici aussi. Allons-y et réparons ça. Mais je veux dire, nous n'avons pas écrit ça bien sûr. Mais c'est un peu l'idée. Tout ce qu'on a à faire, c'est qu'une fois que tu pars et qu'il sera coupé en cubes. Donc c'est une sorte de l'idée qu'une fois que nous avons la classe écrite pour elle, plutôt que nous devons changer d'ordre notre fonction principale et sorte d'adapter tout à cela. C' est beaucoup plus facile que nous pouvons simplement changer les fichiers de configuration. Et en fait, nous pouvons créer plusieurs fichiers de configuration différents
pour plusieurs pipelines différents aimer vouloir exécuter, mais le code va rester le même. Et ce n'est que les différents pipelines que nous avons disponibles. Ou peut-être que vous voulez fournir des valeurs d'entrée supplémentaires avec ce type de format. J' espère que vous pouvez voir qu'il devient beaucoup plus facile de changer, de
manipuler, d'ajouter, de supprimer, ou même d'avoir des flux différents. Eh bien, juste être capable de réutiliser le même code et tout ce que nous changeons vraiment, c'est le flux général et les configurations et autres choses comme ça. Donc, oui, allons-y et retirons cela parce que, bien sûr, cela n'existe pas et nous n'avons pas implémenté ce type de classe. Mais oui, juste un peu plus pour un exemple que vous pouvez voir comment nous pouvons étendre cela et comment cela devient si polyvalent et utile. Parce que encore une fois, nous changeons ce fichier YAML ici et nous pouvons réellement créer plusieurs fichiers YAML différents
pour plusieurs pipelines différents que nous voulons exécuter. Notre code reste toujours le même.
11. Créer un lecteur Yaml: Bon, maintenant que nous avons ce fichier YAML défini, qui va être un pipeline. Allons en fait et implémentons quelque chose qui peut lire ce fichier ou juste prendre un fichier général que
nous supposons avoir ce genre de structure de travail de cube. Et puis il va juste traiter le pipeline pour nous. Parce que notre travailleur Vicki en ce moment n'est pas non plus une menace de soi, mais juste un peu comme une classe qui fait le travail et qui retourne juste un peu les valeurs pour nous. Pour l'instant. Je vais simplement commenter celui-ci ici. Et nous pouvons simplement laisser cela dans notre fonction principale pour maintenant et plus tard si nous le voulons,
nous pouvons changer son collaborateur wiki de refactorisation pour
travailler à la place comme notre ouvrier de Yahoo Finance ou notre travailleur Postgres, où nous avons fondamentalement ce maître ainsi que le travailleur lui-même, mais peut prendre soin du travail afin que nous puissions réellement transmettre
ces valeurs et lire à partir d'un autre Q en amont dans lequel nous pouvons ensuite alimenter ces valeurs. Mais pour l'instant, laissons cela tel quel,
et nous allons juste nous concentrer sur la mise en œuvre de ouais, Fondamentalement tout le reste. Je vais donc créer un nouveau fichier ici. Et je vais l'appeler. Je vais appeler ce lecteur YAML. On pourrait appeler ça quelque chose d'autre comme YAML Pipeline exécuter ou quoi que ce soit. D' accord, et puis ici, pour l'instant je veux juste d'abord, et importer Yaml. C' est quelque chose dont nous allons avoir besoin à coup sûr. Et puis allons de l'avant et définissons juste une classe
, puis importons le reste des choses comme nous en avons besoin. Donc ça va être notre pipeline YAML. On peut l'appeler l'exécuteur de pipeline jaune. Et puis nous allons aller de l'avant et exécuter la méthode d'initialisation, qui pour l'instant laissons juste cette AS vide. Tu reviendras vers nous. Alors, quelles sont les autres méthodes dont nous avons besoin ? Eh bien, tout d'abord, nous avons besoin de quelque chose qui traite une sorte de pipeline, non ? Nous devons être en mesure de traiter le pipe-line que nous voulons passer ici. Il y a donc deux options pour passer les indices de ce pipeline. L' un d'eux est qu'on l'a mis ici. Donc nous pouvons avoir, nous connaissons le nom du fichier ou le répertoire et l'avons trouvé ici que nous pouvons lire à partir de lui. Ou nous pouvons réellement initialiser l'exécuteur YAML Pipeline avec le pipeline que nous voulions exécuter spécifiquement. Je vais choisir cela parce que je pense que c'est un peu plus agréable de
dire que chaque classe que vous avez ici est responsable une fois que vous en
avez une instance en tant que responsable de l'exécution de ce pipeline. Plutôt qu'un exécuteur de pipeline capable d'exécuter n'importe quel pipeline à, il est juste un peu plus facile de
raisonner si vous initialisez un jour ou si vous avez
déjà plusieurs pipelines à exécuter, vous pouvez simplement initialisez différents exécuteurs de pipeline et nommez-les en conséquence, vous un pour chaque pipeline, plutôt que de simplement réutiliser le même, mais en passant dans différents pipelines plus tard. De cette façon, il peut en obtenir un peu plus. Pas confus, mais peut-être comme un peu plus difficile à suivre ou ce n'est pas aussi évident que vous pourriez
obtenir, obtenez-le s'il l'a fait avec l'initialisation. Donc ici, je vais juste dire l'emplacement du pipeline, qui va être trois dans eux. Ou appeler filename est parce que ce sera un chemin qui va être dans les pipelines ici. Donc je veux juste avoir ce genre d'être juste comme un endroit général. Donc, nous allons définir cet attribut. Pipeline. L' emplacement sera égal à cet attribut que nous avons dit ici. Je vais écrire une chanson. Les différentes parties de notre pipeline sont, et si nous regardons aussi notre fonction principale, ok, Alors qu'avons-nous fait de mal ? Besoin d'initialiser les indices. Combien initialiser les travailleurs ? Et puis nous devons envoyer fait aux indices à. Donc, la première chose, bien sûr que nous avons manqué vos deux est que nous devons également lire et traiter ce fichier YAML, ou peut-être que le traitement se produira plus tard, mais nous devons d'abord le lire. Donc, première méthode que nous voulons avoir ce pipeline de charge. Et à partir d'ici, je mets ces soulignements ici juste parce que les soulignements signifient généralement que c'est un peu comme un attribut interne ou une méthode à la classe. Alors qu'aucune ne souligne les méthodes sur quel type de et à utiliser dès le départ. Bien sûr, vous pouvez toujours accéder aux deux en Python que ce genre de vous indique que c'est une méthode que je veux utiliser en interne parce que je ne veux pas quelqu'un d'autre sur le code. Je ne veux pas qu'ils appellent le pipeline de chargement. Et donc ce genre de indique que cela est utilisé en interne. De même, ici, l'emplacement du pipeline est utilisé en interne et ne devrait pas vraiment être désastreux. Parce que, vous savez, nous avons l'emplacement du pipeline défini à partir de l'initialisation. Et donc bien sûr, vous savez, nous devrions charger le pipeline avec le même fichier et cela ne devrait vraiment se produire qu'une seule fois. Et cela devrait être un peu prédéfini et défini comme ça. Alors oui. Donc on doit faire ici c'est qu'on va ouvrir notre jus de goo. Tant de suggestions. Nous allons ouvrir notre fichier et la variable que vous voulez. Et nous allons avoir nos données YAML égales au fichier
d'entrée de charge sans risque de chameau ici. On y va. Très bien, donc c'est une sorte de ce que nous avons fait dans notre dernière leçon pour juste, vous savez, charger le fichier YAML ici, mettre dans cet attribut de données YAML. C' est donc la première étape que nous voulons traiter notre salle de pipeline. La première chose que nous voulons faire est de nous assurer que nous chargeons réellement ce
pipeline. Donc maintenant que nous avons ce fichier YAML chargé dans un objet Python que nous pouvons lire. La prochaine chose que nous voulons faire. Aussi, si nous regardons notre fonction principale, est-ce que nous voulons initialiser nos qs. D' accord ? Nous allons donc avoir une nouvelle méthode. Il va y avoir des vies initiées. Et ils sont du genre ici, cubes. Et oui, à partir de là, nous voulons juste initialiser Qs,
ok, donc maintenant nous devons suivre nos indices d'une manière ou d'une autre. Donc, je vais créer dans notre initialisation et un autre attribut qui va être notre QRS. Et puis nous allons dire pour le nom de la file d'attente, ou en fait il dira pour Q dans nos données YAML. Donc ce qu'on fait ici, c'est qu'on a, ça vient un peu un autre dictionnaire. Depuis lors, nous avons une clé ici, qui est cuz si vous vous
souvenez, ce n'est pas, alors
rapidement, jeter un oeil à cela à nouveau. Nous allons donc importer YAML. Et puis nous allons juste obtenir ce nom correctement. Certains essais avec des pipelines ouverts slash ce serveur, il dirait, oui, je ne sortirai pas avec cette charge sûre. Donc c'est ce que nous allons avoir ici. Et donc dans notre cuz, nous pouvons voir que nous avons cette liste ici et nous avons les différents indices avec leurs noms comme des descriptions pulsives. Donc ce que nous allons faire, c'est que nous allons parcourir ces différents indices que nous voulons. Et pour chacun de ces indices, nous allons créer une file d'attente. Donc, en revenant à notre fonction principale, nous allons le faire en
gros. Et pour obtenir ce Q, nous devons importer cette queue à partir du multitraitement. Donc on va le faire comme ça. Et puis pour chaque file d'attente que nous avons, nous allons dire, ou nous pouvons obtenir le nom de la file d'attente si nous le voulons, qui sera Q2. Nom. Jamais dire, les boucles sont notre nom de file d'attente spécifique dans notre dictionnaire cuz ici va juste
être une version de liste initiale de la classe de file d'attente à partir du multitraitement. Donc on fait la même chose ici. Mais plutôt que de définir ces indices comme ceci, c'est fondamentalement nous avons un objet ou un dictionnaire qui ressemblera à ceci. Bien sûr, vous savez que les noms que nous utilisons sont un peu différents. Mais c'est comme l'idée de ce qu'on fait. Et bien sûr, nous avons la liberté de changer cela en quelque sorte parce que nous pouvons, si nous ajoutons d'autres indices ici, alors cela va juste s'occuper de cela. Mais c'est vraiment le format que nous obtenons ici. Et plutôt que d'utiliser, et je vous verrai dans une seconde, plutôt que de référencer cette variable qui contient le Q, nous pouvons alors juste plus tard sur préférence cette file d'attente spécifique en accédant au composant du dictionnaire. Donc nous faisons toujours la même chose, mais de cette façon, cela nous permet d'abord de distinguer nos différents indices parce que nous avons les différents noms qui leur sont associés. Et cela nous permet également de les mettre à l'échelle un peu plus facilement dynamiquement parce que nous avons un objet qui peut contenir un 0 indéfini. Pendant que nous écrivons ce nombre de codes qui peuvent monter ou descendre selon les besoins. Mais ouais, fondamentalement, vous savez, ce n'est pas vraiment quelque chose de
différent de les placer dans une, une variable distincte. Mais nous n'y accédons pas directement via la variable, mais plutôt via une clé contenue dans un dictionnaire. C' est ce qu'on fait ici. Et bien sûr, c'est ce que nous voulons faire. La prochaine chose que nous voulons faire, c'est bien sûr, initialiser les indices. Bon, donc nous avons chargé notre fichier YAML et nous avons pris soin de cette partie ici. Alors maintenant, allons de l'avant et prenons soin de l'initialisation de nos travailleurs. Alors. Ce sera notre prochaine méthode. On va initialiser les travailleurs. Donc nous allons dire pour travailleur dans les données YAML auto-point. Et cette fois, nous allons faire une boucle sur ces travailleurs comme ça. Et maintenant, nous voulons, eh bien, tout d'abord, nous voulons garder une trace de chacun de ces travailleurs. Donc, nous voulons savoir quels travailleurs nous avons réellement disponibles ou, vous savez, quels travailleurs travaillent actuellement ? Donc vous allez garder une trace de nos différents travailleurs ici, comme ça. Et puis, ok, donc maintenant nous sommes arrivés à un petit problème intéressant parce que nous passons la classe ainsi que l'endroit où nous pouvons trouver cette classe. Mais en fait, c'est juste un nom comme on ne peut pas simplement initialiser ça. Alors que dans notre fonction principale, nous l'avons importé spécifiquement. Alors, comment peut-on faire ça ? Eh bien, il y a une bibliothèque cool que nous pouvons utiliser, qui s'appelle la lèvre d'importation, qui aime, nous permet de prendre soin de cela. Maintenant, une autre chose que vous remarquez également ici, pointant
rapidement cela est
que toutes les bibliothèques qui sont installées par défaut iront tout en haut. Et puis une fois que nous arriverons aux bibliothèques qui sont pip installer et installer à partir d'une source externe, nous allons être séparés par une nouvelle ligne, et ceux-ci vont être regroupés ensemble. Et puis nous pouvons voir dans la fonction principale, nous avons fait la même chose ici. Donc, c'est un interne livré avec Python. Ensuite, nous avons une nouvelle ligne, cette bibliothèque et tout ce qui serait pip install ira ici. Et puis nous avons une nouvelle ligne. Et ce sont tous un peu nos morceaux de
code personnalisés qui sont contenus dans notre dépôt lui-même ici. Donc de cette façon, vous savez, nous sommes en quelque sorte capables de séparer un peu plus facilement les différentes prises de vue de localiser et c'est un peu plus facile de préciser ce qui appartient à quoi. Encore une fois, c'est plus comme une chose visuelle. Bien sûr, tout ce qui est nécessaire. Ça le rend juste un peu plus propre. Je voulais juste le souligner au cas où vous vous demandiez pourquoi je fais ça. Donc, nous avons ce truc important pour la bibliothèque. Donc, bien sûr, ce dont nous avons besoin, c'est que nous avons besoin de la classe de travailleurs que nous pouvons réellement initialiser. Donc, nous voulons être en mesure de lire cette classe générale de travailleurs pour que nous puissions faire quelque chose comme ça. Mais bien sûr, nous ne savons pas quels travailleurs nous allons
obtenir parce que ce pipeline peut vraiment être défini. Cependant, n'est-ce pas ? Comme si c'était la chose géniale. Mais bien sûr, 0 remarqué point gauche dans la dernière fois. C' est la grande chose. Mais bien sûr, nous devons aussi être en mesure d'y faire face correctement. Donc, pour ce faire, nous allons utiliser le membre d'importation ou en fait si nous allons utiliser le premier attribut. Et je t'expliquerai, écrivons tout ça et je t'expliquerai tout ici dans une seconde. Et nous allons faire importer le module d'importation de point lib. Et le module que nous allons importer sera l'emplacement du travailleur. Nous allons donc accéder au travailleur spécifique et nous allons
accéder à son emplacement spécifique. Et puis l'attribut auquel nous voulons accéder. Et encore une fois, écrivons ceci et reprenons une fois de plus. Il va y avoir la classe ouvrière. D' accord. Alors qu'est-ce qu'on vient de faire ? Jetons un coup d'oeil à nos ouvriers. Jetons un coup d'oeil à notre premier travailleur ici. Donc vraiment, vous savez, bien sûr, si nous faisons une boucle sur ces travailleurs, alors nous allons avoir chacun de ces éléments ici un par un. Donc nous avons le nom, et cetera, et cetera. ce moment, nous regardons l'endroit. Celle-ci ici. Donc ça nous donne ce truc ici, non ? Ce chemin travailleurs dot yahoo travailleur financier, travailleurs dot yahoo travailleur financier. La même chose que nous avons fait ici. Travailleurs dot yahoo Travailleurs financiers. D' accord ? Donc, notre boucle d'importation va importer ce module comme ceci. Donc, fondamentalement, il va faire quelque chose comme l'importation. Et puis il va juste importer, importer ceci. Fondamentalement, ça nous permet de faire ça. Parce que nous ne voulons pas seulement tout ce module, mais plutôt nous voulons obtenir une classe spécifique à partir de celui-ci. Nous devons obtenir un attribut spécifique de cette classe. Maintenant, c'est une méthode Python interne qui nous permet essentiellement d'accéder aux attributs. Cela fonctionne en fait de la même façon. Si nous avions comme une classe définie spécifique, nous pourrions prendre notre classe ici
et, disons que nous le voulions. Nous avons notre programme Yahoo Finance. Je regarde et jette un coup d'oeil là-dedans. Donc, ici, nous avons les files d'attente d'entrée. Donc quelque chose que nous pourrions faire est que nous pourrions dire comme Get attribut ici, et ensuite nous avons les files d'attente d'entrée. Et donc fondamentalement, c'est une sorte de moyen pour nous de retirer des attributs des classes, ou dans ce cas aussi des modules. Parce que faire quelque chose comme ça ne fonctionne pas réellement pour les classes et les œuvres ou les dictionnaires, mais cela ne fonctionne pas pour les classes que nous aurions besoin de faire,
est-ce qu'il y a accès comme ça, non ? Mais que faire si nous voulons accéder dynamiquement à une variable ? Alors nous ne pouvons pas juste comme il n'y a pas de bon moyen nous puissions avoir cette syntaxe si c'est censé être dynamique. Donc, la façon dont nous pouvons le faire est d'utiliser cette méthode get attributes. Et, et cela nous permet de
définir dynamiquement l'attribut que nous voulons prendre de cette classe comme ceci. De même, nous pouvons utiliser la même épaisseur, mais cela fonctionne également sur ce module d'importation ici. Donc nous l'importons et à partir de là nous extrayons cette classe de travailleurs. Donc, fondamentalement, cette chose ici est presque la même chose que de faire ça ici, sauf que nous sommes spécifiquement déjà, vous savez, nous avons ce cours que nous prenons maintenant. Et nous l'avons spécifiquement dans cette variable de classe de travailleur ici afin que nous puissions l'utiliser et nous pouvons l'initialiser. Donc, bien sûr, nous devons les faire parce que, encore une fois, tout
cela peut être défini à volonté. Et donc nous devons pouvoir réellement importer la classe et l'utiliser ou l'initialiser et l'utiliser sans savoir quelle classe cela va être. Nous avons un peu besoin, tant que nous avons ce format de classe de localisation, vous savez, tant que cela est respecté, nous devons être en mesure d'importer cela et de l'initialiser. Très bien, donc nous avons notre classe de travailleurs, mais nous avons aussi besoin d'autres propriétés qui lui sont associées. Des choses si importantes si nous regardons nos deux travailleurs ici c'est que nous avons besoin de l'entrée q et que nous avons besoin de la sortie QS. Si nous regardons notre travailleur Postgres ici, nous avons seulement besoin de la file d'attente d'entrée. D' accord ? Donc, nous allons juste lire la file d'attente d'entrée. Et c'est cet attribut ici que nous avons défini avec les travailleurs. Donc nous allons dire notre ouvrier. Et ici, ce que nous allons faire est plutôt que d'essayer d'accéder à l'attribut directement comme ceci. Parce que dans certains cas, par
exemple, si nous avons ceci défini, cela ne fonctionnerait pas parce que nos files d'attente d'entrée ne sont pas définies ici. Donc, pour être en sécurité contre quelque chose comme ça, nous allons en fait utiliser une méthode point get. Maintenant, je veux te montrer ça très vite. Donc, si nous avons un dictionnaire, comme celui-ci, très simple dictionnaire, si vous faites x point obtenir un, nous allons obtenir la valeur de la clé a, qui cartes pour être ici. Mais si vous faites x point obtenir dire, un ou la chaîne 1. Donc, c'est à la recherche de la clé. Cette valeur n'est pas ici, donc nous n'en aurons aucune. Donc, de cette façon, plutôt que cela échoue, il va soit obtenir la valeur ici si elle existe ou n'existe pas, il n'en aura pas. D' accord ? De cette façon, nous pouvons, vous savez, nous allons être sûrs que nous n'échouons pas ici. Nous voulons également la sortie QS. Et à partir de là, nous allons simplement utiliser ce format. Ce sera notre QS de sortie ici. D' accord ? Et voyons, avons-nous besoin de quelque chose d'autre ? Nous avons donc besoin de nos valeurs d'entrée et de notre cube supérieur. Bon, donc on a ça dedans. Mais actuellement notre file d'attente d'entrée ici, il sera en fait juste un nom. Ce n'est pas la file d'attente elle-même. Donc nous devons obtenir ces indices et ensuite nous pouvons les transmettre à nos ouvriers. Nous allons donc nous asseoir à la fois, nous allons créer une nouvelle variable qui sera nos paramètres d'initialisation. Et ici, nous allons passer la file d'attente d'entrée, que nous allons définir. Et nous allons aussi nous avoir pour l'instant juste les files d'attente de sortie, qui vont également définir en seulement une seconde. D' accord, donc ici, on doit passer une instance de ce mignon comme ça, non ? On ne peut pas passer le nom. Cela parce que c'est juste un nom n'est pas utile. Donc pour ça, nous avons nos indices ici. Donc ce que nous voulons faire c'est que nous voulons essentiellement obtenir cette file d'attente d'entrée ici. On veut l'avoir. Nous voulons obtenir l'instance de file d'attente réelle. Donc, nous allons dire self.users dot input, oops, et mettre QM. Si vous mettez q n'est pas nul. Aucun. Alors, comment avons-nous défini cela ? Oh, oui, bien sûr qu'on a besoin de la virgule après. Donc, il y a juste un raccourci si else déclaration que nous pouvons écrire sur une ligne afin que nous n'ayons pas à l'écrire sur plusieurs lignes. Mélanger un peu plus facile d'avoir que sur quelles lignes, nous pouvons avoir toute cette logique ici directement. Donc, si nous avons une file d'attente d'entrée, alors nous allons prendre l'instance réelle que nous avons définie ici et utiliser n'importe quel Q est associé à cela. Sinon, ce ne sera qu'aucun. Et voici ce qu'on veut faire. Est une chose similaire, qui va être, nous voulons. Maintenant, ici, nous devons être prudents parce que nous pouvons avoir plusieurs QS de sortie, non ? Donc, nous voulons faire ça plus comme si nous voulons en faire une liste. Quelqu' un répond à dire ici, hors point point de sortie Q. Pour la sortie Q. Et les indices. Si aucun, bien sûr, c'est un peu long. Est-ce que je passe sur le nombre de lignes recommandé ? Nous pouvons diviser cela sur 2 ions en mettant juste une barre oblique inverse ici, ce
qui nous permet de diviser cela sur deux lignes. Ok, donc maintenant nous avons nos paramètres d'initialisation. Encore une fois, ce que cela fait, c'est qu'il nous permet casser une instruction sur plusieurs lignes sans casser la logique. Parce que si on faisait ça ou la logique serait brisée, non ? On a juste cette liste ici. Et puis la ligne suivante, nous exécuterions la déclaration. Ce sera hors de cette année. Il rejoint en fait cette logique ensemble et dit
fondamentalement que cette logique continue à droite sur la ligne suivante. Et de cette façon, nous n'avons pas à faire face à ce texte débordant. D' accord, donc nous avons la cellule Paramètres d'initialisation de nos instances de travail ici. Alors, allons de l'avant et initialisons nos travailleurs. Donc, tout d'abord, je veux juste aussi vouloir les obtenir ou pourrait nommer, bien
sûr, nom propre. Ça va extraire le nom. Donc, pour chaque nom de travailleur, pour l'instant je vais juste créer une liste vide pour cela, puis nous allons ajouter les différentes causes de travail. Donc pour l'instant, je vais dire des courtiers autodidactes que le travailleur nommé dot append et avoir ces classes de travailleurs ici. Et nous allons lui transmettre les paramètres d'initialisation. Donc, cela nous permet de faire,
est-ce qu'il prend ce dictionnaire et il transforme fondamentalement chaque dictionnaire
ici en une paire de valeur clé que nous pouvons passer. Donc, ce qui se passerait dans ce cas est de faire cela est la même chose
que d'avoir quelque chose comme si notre entrée q ici n'est pas en boucle comme ceci. Et ce serait, par exemple, autodidacte cuz si nous prenons, eh bien, prenons l'exemple pour le jeune travailleur financier. Et je devine juste ici. Et puis passons en revue ce qui se passe. Donc, cette étoile, étoile décompresse fondamentalement ce dictionnaire et pour chaque clé ici, a la clé ici est ceci, puis la mappe à une valeur spécifique dans le dictionnaire comme ceci. Et il le fait dynamiquement. Donc, si vous ajoutez plus de paramètres ici, alors tous ceux-ci, vous savez, chacun d'entre eux sera défini dans un mappage de paires de valeurs clés ici. Donc, c'est vraiment sympa parce que cela nous permet de décompresser nos paramètres d'initialisation et de les passer individuellement, comme des paires de valeurs clés ici afin que nous
puissions spécifiquement définir comme ceci est un très particulier leurs files d'attente de sortie, bien sûr, pour que cela fonctionne, nous devons nous assurer que ceux sont nommés ici, entrée q et q. Donc, cela va déjà être un problème parce que j'ai appelé cette file d'attente de sortie, mais cela est appelé sortie cubed ici, donc qu'il va le créer comme ça. Maintenant, un autre problème, bien sûr, est si nous fournissons ici des paramètres qui n'existent pas. Par exemple, dans ce cas, nous avons tous les deux des entrées ici. Nous n'avons pas de Q supérieur. Donc vraiment si nous avons juste ceci ici, alors il se plaindrait parce que nous transmettons Q de sortie comme paramètre d'initialisation. Mais il n'existe pas chez le travailleur Postgres. Mais c'est là que ces étoiles, star K Works. Ou les arguments de mot clé entrent dans. Fondamentalement nous permet de passer un ensemble E d'arguments de mots-clés. Donc, tout ce qui est défini avec le mot-clé et défini égal à quelque chose sans vraiment avoir à s'inquiéter, vous savez, comme les répercussions. Il suffit de le prendre et ensuite on peut en faire ce qu'on veut si on veut l'utiliser. Dans ce cas, nous le transmettons simplement au thread à la classe parent. Mais nous pourrions aussi ignorer complètement cela et ne rien faire avec. Bonjour. C' est une façon vraiment sympa de le faire parce que nous pouvons juste décompresser ce dictionnaire et immédiatement, vous savez, le passer ici. Et oui, donc nous avons presque la logique que nous avons ici. Il manque encore des choses. Par exemple, nous définissons ici le nombre de travailleurs que nous n'avons pas actuellement. C' est une solution facile pour nous parce qu'on peut juste entrer ici. Et nous pouvons dire, par exemple, des exemples. Disons que nous voulons la forme. Et je prendrai la même chose et je mettrai ça ici. Ce n'est pas forcément le même ordre. Encore une fois, nous obtenons un mappage de dictionnaire à partir de ceci. C' est juste le moment idéal pour être le même ordre. Et ici, nous pouvons dire, ou Disons que nous voulons beaucoup de travailleurs Postgres, mais nous ne voulons pas autant de scrubbers. Donc maintenant, nous pouvons dire que le nombre d'instances que nous voulons est juste obtenir les attributs d'instances d'ici, comme ceci, et ensuite plutôt simplement l'initialiser une fois que nous allons
dire que je dans la plage le nombre d'instances. Et nous voulons créer des travailleurs Domini. Ici. En fait, ce serait probablement mieux pour nous de faire quelque chose comme ça. Et nous pouvons également faire est de mettre un paramètre par défaut ou un paramètre de secours. Donc, dans ce cas, si nous revenons à ce point x a, nous obtenons la valeur b qui est associée au k ici. Si nous faisons x dot dot voulait exister. Mais si nous faisons cela, cela signifie
que si cela n'existe pas, alors nous revenons par défaut à cela. Donc, si pour une raison quelconque les instances qu'il n'est pas défini, nous savons que nous voulons travailler avec cela parce que c'est dans le pipeline. Donc on va juste en utiliser un. Sinon, si l'artefact des instances et nous allons l'utiliser. De cette façon, nous pouvons maintenant augmenter dynamiquement si nous
voulions ou diminuer chaque fois que nous voulons le nombre de travailleurs ici, et nous allons simplement créer autant de travailleurs. Et puis la dernière chose que nous voulons faire est, bien
sûr, nous voulons appeler cette méthode auto-point initialiser les travailleurs. Et puis nous voulons aussi être en mesure de rejoindre les travailleurs comme nous l'avons ici. Donc, les travailleurs et nous avons déjà dit pour travailleur en, les travailleurs diront pour déformer le nom et les travailleurs, puis nous dirons pour le fil de travail. Alors rappelez-vous que nous avons un, c'est un dictionnaire et chaque clé ici est le nom du travailleur. Et puis avec chaque valeur, nous allons avoir une liste. Et chacune de ces listes sera une classe de travail. Donc, chacun d'entre eux sera un thread en cours d'exécution. Donc, nous voulons faire une boucle sur chaque thread. Et puis ici, nous appellerons le point jointure comme ça. Bon, donc ça va être la classe. Et nous allons nous arrêter ici pour l'instant parce que nous sommes évidemment que cette classe est implémentée n'importe où, mais cela va être un peu, cela forme la base de sa classe qui nous permet de faire toutes ces choses. Donc, les leçons suivantes, nous allons implémenter cette classe et en quelque sorte la déplacer vers notre fonction principale et, vous savez, la fonctionnalité là-bas. Nous allons faire n'importe quel débogage, bien sûr, parce que nous n'avons pas pu tester cette classe du tout, d'accord, maintenant c'est juste un peu écrit comme ça. Donc, il est probablement probable qu'il y ait des bugs ici que nous allons devoir corriger. Certains le font aussi et ensuite, en quelque sorte, prennent le dessus. Et peut-être alors aussi changer une fonctionnalité un
peu pour que nous puissions réellement avoir notre travailleur wiki ici aussi quelque chose que nous pouvons définir
comment nous voulons être en mesure de peut-être passer dans plusieurs URL. Oui, mais oui, je suppose qu'on va faire ça dans les leçons suivantes, puisque tu ne veux plus nous traîner trop longtemps ici.
12. Améliorer notre travail : Travailler dans Wiki: Bon, maintenant que nous avons ce YAML, nous allons trouver. Allons de l'avant et implémentons cela dans notre classe principale parce que
maintenant nous sommes sur notre fonction principale parce que pour le moment nous avons juste ce coût très bien, mais nous ne faisons pas vraiment grand-chose avec. Et ce n'est pas encore parfait comme on le verra dans une seconde. Mais nous allons dire par la rigueur M, nous allons importer l'exécuteur YAML Pipeline. Bon, donc nous allons avoir notre exécuteur YAML Pipeline être égal à. Et maintenant, nous devons définir l'emplacement du pipeline. Donc notre emplacement de pipeline à partir
de maintenant sera pipelines slash wiki, point
YAML de pipeline de cuivre de Yahoo. Maintenant, c'est assez codé en dur. Idéalement, il le déplacera vers les variables d'environnement, mais nous le ferons plus tard. Allons juste faire fonctionner ce truc pour l'instant. D' accord, donc nous n'avons plus besoin de cela parce que nous avons notre exécuteur YAML Pipeline ou des travailleurs wiki. Intéressant, parce que nous en avons encore besoin. On n'en a plus besoin. Et cela, nous n'avons pas besoin non plus. Nous devons donc changer un peu notre pipeline de traitement parce que nous ne pouvons pas, nous verrons dans une seconde, mais nous ne pouvons pas encore rejoindre les travailleurs. Parce qu'en ce moment, il y a un peu comme ça. Pas au hasard, mais comme si c'était un peu toujours pas parfait parce que nous
avons des trucs dans le YAML et l'exécuter et des trucs comme nous le verrons dans une seconde toujours sans elle. Donc si on appelle le pipeline de processus ici, on va charger le pipeline. Nous allons initialiser un QRS et des travailleurs. Nous ne voulons pas nous joindre parce que si nous faisons ça, alors, vous savez, je suis fondamentalement tous les travailleurs étaient un peu finis et ensuite nous n'avons rien mis dans,
mais nous ne pouvons pas encore mettre quoi que ce soit dedans parce que les q ne sont initialisés qu'une fois que nous initialise réellement la file d'attente et l'étape de pipeline de processus ici. Donc, malheureusement, pour l'instant, nous allons corriger ça plus tard, mais pour l'instant nous allons devoir éteindre ce joint ici et nous allons devoir l'appeler manuellement plus tard. On n'est pas manuellement, on va l'appeler plus tard. Donc nous avons notre symbole Q. Maintenant, le Q que nous voulons. Pour l'instant, je vais juste les utiliser. La valeur codée en dur sera ce symbole Q ici. Et bien sûr, maintenant nous voulons faire tout ce genre de ce pipeline YAML, je pense ici. Donc, mais pour l'instant, nous allons juste tester la fonctionnalité. Donc tu vas aller dans notre exécuteur de pipeline YAML. Nous allons réellement accéder à cet attribut. Et ici, nous allons accéder au,
le symbole Q, parce que c'est là que cela doit être écrit dans. C' est donc la clé que nous voulons écrire dans, bien
sûr, la syntaxe non idéale. Mais parce que notre collaborateur wiki n'est en fait pas défini le pipeline et dans l'uretère ont un peu à le faire comme ça pour l'instant. D' accord. Puis l'impression est faite par la suite. Donc, actuellement, nous devons aussi le faire. Hum, donc pour l'instant, nous, parce que nous pouvons maintenant définir comme le nombre d'instances différentes ici par nous-mêmes. On va juste prendre une grosse casquette supérieure. Et nous allons dire, au lieu de, vous savez, spécifiquement dire un certain nombre, nous allons juste dire 20 images. Mais bien sûr, ce n'est pas idéal non plus. Mais, tu sais, faisons que ça soit comme ça pour l'instant. Nous allons mettre fait au symbole q. Et ici où les fils sont joints, ainsi de suite. D' accord. Donc maintenant, nous devons rejoindre nos menaces et montré une autre syntaxe, essayer et travailleurs. Faisons en sorte que tu rejoignes les planeurs, d'accord ? Bon, alors allons de l'avant et allons voir si ça marche. Probablement des bogues que nous devons corriger. Bon, donc notre travailleur Postgres a obtenu une sortie d'argument de mot-clé inattendue Q. Alors jetons un coup d'oeil à cela. Travailleur de Postgres ici. J' ai une vraie inattendue. Où est notre problème ? Travailleurs initialisés, classe de travail. Ok, alors pense que le problème c'est que tu fais Postgres Master Scheduler. Non, ce n'est pas le problème. Maître Postgres. Et il a obtenu une sortie d'argument de mot-clé inattendue Q. Donc, en regardant notre journal ici, il semble que cela se plaint dès que nous faisons la super initialisation. Donc peut-être ou le nuage de threads est, classe de
thread se plaint en fait de ceux-ci. Alors testons ça. On va aller en Python. On va importer. En écrivant, nous allons dire fil de point de filetage. Et essayons juste la sortie Q est égale à a. Donc, c'est là que le problème est. Donc, nous allons faire confiance, mettre ce Q de sortie ici, sorte que nous ne le transmettons pas aux arguments du mot-clé ici. Alternativement, vous pouvez également faire est que nous pouvons le supprimer de ce dictionnaire en utilisant cet appel pop, qui va juste le supprimer et en fait sorte de nous donner la valeur ici, mais il va juste le supprimer des arguments du mot-clé. Donc, et ici nous voulons probablement avoir un peu de sécurité. Vous voulez dire si la sortie Q et les arguments de mot-clé, alors nous voulions simplement le supprimer. Essayons de courir ce temps de femme. D' accord. Jusqu' à présent pas d'infirmières, probablement bon signe. D'accord. Donc, nous avons atteint une sorte de délai d'attente qui va bien. Mais on dirait que c'est fini. Donc, nous avons eu une sorte de temps approché pour quelque raison que ce soit pour l'instant. Mais bien sûr, cette fois je viens d'ici. Si jeune. Mis à part ça, on dirait que ça marche. Donc, en fait, c'est plutôt génial. Cela signifie que nous pouvons prendre ce code et nous pouvons voir ce qui reste et ce qui doit être mis en œuvre. Ok, donc bien sûr, une des choses que nous voulons passer est que tout ça n'est pas très gentil, non ? Comme idéalement, nous aurons le travailleur wiki. Et tout ce processus que nous gardons les valeurs des travailleurs est alimenté. Et tout cela se fait dans cette souche de pipeline de processus. Et de cette façon, nous n'avons pas à les appeler rejoindre et à se récurrencer ici non plus. Alors, comment allons-nous faire ça ? Donc, le meilleur moyen ou non, je pense que la façon dont je voudrais le plus est que nous étendions un peu à ce travailleur wiki. Et fondamentalement ce que nous allons avoir comme vouloir avoir un genre d'option similaire où nous avons cette masterclass pour laquelle nous pouvons fournir des valeurs. Et à partir de ces valeurs, alors nous allons avoir, vous savez, instances de travail
wiki ou juste une seule instance de travailleur Wiki, peut-être que cela va s'occuper de cela. Donc, ce que nous pouvons faire, c'est que nous pouvons avoir un planificateur maître de travail wiki. Et nous allons également avoir en fait ce soit une instance de thread de point de thread. C'est déjà à notre crédit. Joli. Donc, la raison en est que dans notre lecteur YAML, nous allons en fait appeler la méthode join. Et sinon, de cette façon, Nous obtenons comme un bon appel de la méthode join car elle vient héritée de la classe de thread. Mais sinon nous aurions besoin de le définir nous-mêmes pour que quand nous l'appelons rejoindre, vous savez, il ne se casse pas. Et tu pourrais même le faire en faisant quelque chose comme ça. Il est juste disponible. Vous savez, si, si elle n'est pas héritée de la classe parent, juste pour qu'elle ne casse pas dans cette étape afin que nous puissions suivre ce même type d'ordre logique. Mais faisons en fait un menacé et allons de l'avant et initialisons le parent. Ici, nous allons prendre des arguments de mots-clés. Encore une fois, passer fréquemment au parent de thread. Oui. Fin. Que voulons-nous dans notre ouvrier Vicki ici a appelé l'une des choses que nous voulons faire. Bien sûr, je ne peux pas oublier si tu veux commencer. Et puis nous devons aussi avoir des frais hors classe ici. Et on va faire quelque chose, tu sais, pendant que tout ce que c'est vrai. D' accord ? Alors, qu'est-ce qu'on veut dans notre programmateur principal Mickey ? Donc, si nous jetons un coup d'oeil à notre fonction principale ici, nous voulons que notre travailleur soit en mesure de prendre des URL d'entrée différentes, créer un travailleur wiki avec chaque URL, puis que ce travailleur wiki sorte de passer par son processus obtenant les symboles et en les mettant simplement dans un Q. Donc, ce dont nous avons besoin pour cela que nous avons besoin si la sortie Q. Et à partir d'ici, nous voulons nous assurer que vous ne passez pas la file d'attente d'entrée parce que cela aura la même plainte. Donc, nous allons dire que si notre entrée q est dans nos arguments de mots-clés, nous le supprimons et juste sauté de cela. Et une autre chose que nous voulons, c'est que nous voulons vraiment une sorte d'entrées que nous pouvons transmettre, non ? Comme nous n'avons pas de file d'attente d'entrée parce que nous n'allions pas lire à partir d'une file d'attente d'entrée, mais nous voulons des entrées que nous pouvons parcourir. Donc nous allons dire, nous allons supposer que nous allons
passer et que les entrées vont dire entrées. Et bien sûr, nous ne voulons pas non plus passer les entrées. Donc entrées chambre à prendre à partir d'ici. Et on va sortir de nouveau comme ça. D' accord, donc oui, c'est le format qu'on veut. Bien sûr, nous voulons également régler la sortie Q à l'accusé. Et nous allons en fait utiliser la même syntaxe que nous utilisons ici. Pour que nous puissions définir plusieurs QS de sortie si nécessaire. Si nous revenons ici, de
cette façon, chaque fois que nous obtenons des valeurs,
si nous le voulons, nous pouvons les mettre dans différentes files d'attente de sortie afin que, vous savez, différents travailleurs en amont puissent les utiliser à quelque fin que ce soit. En utilisant cela pour, ok, Si Q2 et ok, donc maintenant nous devons définir ces entrées et nous allons également changer notre méthode d'exécution ici. Donc, plutôt que de dire bien que vrai, nous allons dire pour l'entrée et aventure est parce que maintenant nous avons un nombre limité d' entrées qui espèrent que nous voulons passer sur cela. Et je suis la somme de rang. Mettons à jour notre fichier YAML afin que nous voulons que notre wiki se produise. Et plutôt que d'initialiser Bucher freaky bras, nous voulons initialiser l'ordonnanceur maître de travail wiki. Nous avons appelé ces valeurs d'entrée. Donc, si vous voulez, nous pouvons mettre à jour à partir des entrées ici deux valeurs d'entrée. C' est tout à fait bien. Le fait est que je dois m'assurer que, bien sûr, nous le faisons également ici. D' accord ? Donc, nous voulons prendre les valeurs d'entrée ici. Et puis pour chaque valeur d'entrée comme celle-ci, nous voulons itérer sur celles-ci. Et pour chacune de ces valeurs d'entrée, nous voulons juste mettre ces valeurs dans le symbole de sortie Q ici. Bon, donc nous avons nos entrées ici. Donc, pour chaque entrée, nous allons ensuite avoir sur notre Wiki Corker, nous voulons initialiser ceci. Nous voulons réellement l'initialiser avec une URL spécifique. Donc, ce que nous allons faire, c'est que nous allons déplacer l'URL dans les paramètres d'initialisation ici. Et de cette façon, nous pouvons l'initialiser directement pour les différentes entrées que nous allons fournir par ici. Et maintenant, nous devons aussi, eh bien, si nous revenons à notre fonction principale, nous pouvons itérer sur les différents symboles et ensuite nous voulons les mettre dans notre sortie Q. Donc, pour l'instant, nous pouvons simplement reprendre cette logique en utilisant la compteur de symbole à cela. La seule raison pour laquelle nous utilisons ceci est à nouveau, rappelez-vous, afin que nous ne mettons pas tous les symboles dans la sortie Q afin que nous éliminions toutes ces différentes valeurs, les
appliquer dans Postgres. Et, mais plutôt nous faisons juste les cinq premiers juste pour nous assurer que ça marche. On n'a pas besoin de faire comme tous les 500 en ce moment. Donc on va prendre le contrôle de ce logement et on va avoir, je suis plus vieux. Je vais dire quatre,
mettre q dans nos files d'attente de sortie. Donc, pour chaque sortie Q, Oops, Non, nous voulons nous assurer de mettre ce symbole là. C' est vrai ? Alors passons en revue cette logique ici. Donc, nous avons notre planificateur maître de travail wiki, qui va être une instance de la classe de thread. Pour cela, nous allons prendre les arguments de mots-clés et la sortie Q. Et si nous n'avons pas d'entrée q et nous voulons nous assurer que cela est supprimé afin que nous ne le transmettions à l'initialisation de la classe parent de thread. Nous voulons également des valeurs d'entrée, et ces valeurs d'entrée vont être des URL différentes que nous pouvons définir ici comme ceci. Et bien sûr, pour notre cuz de sortie, nous voulons nous assurer que nous
avons la possibilité d'avoir différents indices alpha pour que nous puissions avoir ici, par
exemple, le symbole Q2 et le second symbole Q. Et si nous avons ceci, laissez-moi aussi bien sûr besoin de le définir ici, mais, vous savez, juste si nous voulons mettre cela à plus d'un Q, donc je suis plus d'un type différent de travailleur peut consommer ce que nous avons cette option en aval. On veut s'assurer d'initialiser un thread parent. Et puis nous voulons commencer le processus, comme nous le faisons ici. Maintenant, pour que cela fonctionne, nous avons aussi besoin de la méthode run, qui va s'appeler Kind dont on peut s'occuper automatiquement pour nous parce que nous jetons parent. Mais différent de nos travailleurs en aval qui vont attendre des valeurs jusqu'à ce qu'elles sortent du QRS et les lisent. Différent de ça. Nous ne lisons pas d'une aiguë ici, mais nous lisons à partir d'un ensemble prédéfini d'entrées. Donc oui, nous voulons juste nous assurer que nous étions en train de passer par l'ensemble prédéfini d'entrées que nous avons ici, parce que nous savons déjà quelles sont ces valeurs. Donc on n'a pas besoin, tu sais, d'essayer de les obtenir d'une sorte de mignon. Donc nous allons passer en revue les différentes URL d'entrée. Pour chaque entrée, vous allez créer un travailleur wiki. Ce travailleur wiki va prendre soin de la mise au rebut, donc trouver chacun des symboles. Donc nous allons avoir la même logique ici. Et pour chaque symbole que nous obtenons, nous voulons le mettre à la sortie QS, puisque nous pouvons avoir plusieurs jeunes olympiques, nous voulons nous assurer que nous bouclons sur chaque Q. supérieur Et puis ce truc ici, c'est vraiment juste pour que nous ne détruisions pas 500 symboles, mais seulement les cinq premiers pour le faire passer un peu plus rapidement. Bon, alors prenons cette sortie et à la fin. C' est donc aussi logique que nous voulons réellement passer dans notre travailleur rapide. Et à la fin ici, je veux dire pour la sortie Q et les indices supérieurs. Et là encore, on va juste dire comme un chiffre ridicule en ce moment. 20. Nous voulions nous assurer que nous envoyons. Et nous voulons que cela arrive seulement après, vous savez, tous les symboles ont été envoyés. Et puis une fois que tout ce qui est terminé, nous pouvons réellement envoyer fait. Donc on n'a plus besoin de ça ici. Nous n'avons plus besoin qu'ils rejoignent les travailleurs parce que nous pouvons le faire maintenant. Et ici. Et je vais écrire, et jetons un coup d'oeil à ça. Bon, alors allons-y et essayons de savoir, voir ce qui se passe. Voyez si on a manqué quelque chose. C' est vrai ? Donc, il est à la recherche des valeurs d'entrée
0, 0, cours, et notre lecteur jaune. Nous devons aussi nous assurer que nous passons écouter. Par conséquent, les valeurs d'entrée sont égales à point de travail. Pourtant, les valeurs d'entrée. En fait, je vais faire ça ici. Et je vais dire, si j'utilise n'est pas une anomalie, alors je veux les mettre dans les paramètres d'initialisation. La raison pour laquelle je fais cela, plutôt que de toujours fournir la moyenne et les paramètres d'initialisation, comme nous le faisons ici, est parce que nos valeurs d'entrée sont un peu comme un cas particulier, spécifiquement pour notre travail wiki ici, droit ? Parce que dans tous les autres travailleurs, il y aura des accusés, peut-être pas les accusés avec ils seront vraiment comme des files d'attente d'entrée et de sortie. Mais nos valeurs d'entrée ne vont vraiment être spécifiques qu'à notre seul travailleur ici. Donc, plutôt que de le mettre ici et ensuite d'aller dans autre travailleur et de s'assurer que cette file d'attente d'entrée, ces valeurs d'entrée ne sont pas transmises comme arguments de mot-clé vers le bas au thread, comme l'initialisation de thread ici. Je vais juste le transmettre si c'est vraiment
là-dedans et de cette façon, je n'ai qu'à m'en occuper ici. D' accord, alors essayons encore. Aucune erreur jusqu'à présent, ce qui est généralement un bon signe. Mais attendons et voyons ce qui se passe. D' accord. Cool. Donc, on dirait que les choses fonctionnent. Et oui, nous avons notre collaborateur wiki maintenant que, vous savez, prend toutes ces valeurs. Mais bien sûr, pour s'assurer que les choses fonctionnent, Allons-y et imprimer dans notre travailleur Postgres a reçu cela juste pour voir si elle arrive tout le chemin, tout le chemin vers le bas flux. Très bien, donc il reçoit des valeurs. Donc tout fonctionne, ce qui est génial. Il y a, bien sûr, toujours une chose qui ne fonctionne pas, qui est qu'il ne reçoit pas
correctement fait tout le temps et ce n'est pas comme s'échapper probablement. Et la raison pour ça, si on allait chez Yahoo Finance, c' est en fait que c'est seulement de mettre fait ici. Et donc le problème ici, dans ce cas, c'est que
si nous allons ici, nous avons deux cas, mais nous avons six cas ici. Donc vous remarquerez que la différence, six moins deux est quatre. Nous avons quatre instances qui ne reçoivent pas, qui sont faites signal en ce moment. Donc ce qu'on peut faire pour l'instant, c'est juste enlever ça parce qu'ils s'échappent. Et nous allons dire ici, pour Alpha q et jusqu'à accuser ticket dira juste pour moi dans la portée 20. Pour chaque sortie Q, nous allons juste envoyer un tas d'entre eux. Bien sûr, ce n'est pas idéal parce que si nous avons 21 travailleurs et beaucoup du même problème, mais pour l'instant, vous savez, ça devrait aller. Donc, nous pouvons juste réexécuter rapidement ça. L' autre chose que vous remarquerez également est qu'il n'a pas défini les instances ici. Et de cette façon, vous pouvez voir ça, super, et tout a bien fonctionné parce que nous n'avons pas défini comme les instances ici. Cela a pris soin de ça. Maintenant c'est une autre petite nuance que nous avons car ici nous ne voulons pas vraiment plusieurs instances. Parce que si nous avons plusieurs instances, elles ne vont pas consommer à partir de la même file d'attente, mais au lieu de cela ils vont répéter ce processus. Donc ici, nous ne voulons pas de plusieurs instances parce que si nous le faisons, comme je l'ai dit, ils ne consomment pas d'une file d'attente. Donc ils ne prennent pas de repère et ne divisent pas le travail. Ils vont répéter le travail parce que la façon dont cela
fonctionne est qu' il va réellement itérer sur ce jeu de valeurs d'entrée. Donc, ici, nous devons faire attention que nous n'avons que 11 instances. Donc, nous pouvons laisser, par exemple, sur note, n'avoir qu'une seule instance ici. Sinon, nous supprimons ce symbole. Donc, bien sûr, vous savez qu'il y a différentes façons d'y arriver. Une chose que nous pourrions faire est que nous pourrions à nouveau aimer un ceci séparé et vous savez, juste avoir notre travailleur wiki lui-même consommé à partir d'une file d'attente. Et nous alimentons ces valeurs d'entrée dans q lui-même. Mais à un moment donné, vous savez, nous avons besoin, avez-vous besoin d'arriver au point où soit nous avons un travailleur qui n'
a qu'une seule instance qui alimente toutes
ces valeurs d' entrée dans une file d'attente que le travailleur wiki pourrait ensuite consommer. Donc, par exemple, nous pourrions avoir comme un autre travailleur ici, juste être, vous savez, URL cèdre. Et celui-ci ici peut prendre comme celui-ci ici pourrait prendre ces valeurs d'entrée. Et puis les files d'attente de sortie. Les files d'attente peuvent, par exemple, être des sorties d'URL. Et puis ici et mettre Q, nous pouvons lire d'ici. Et dans ce cas, comme ce travailleur va être celui qui ne peut avoir qu'une seule instance. Et peut-être que c'est, tu sais. Donc, comme ce problème va être un peu comme étendu vers l'avant, vers le haut. Mais dans ce cas, nous pouvons avoir plusieurs threads ici car ils ne vont plus lire à partir de valeurs d'entrée, mais ils vont créer à partir de la file d'attente d'entrée. Hum, donc si vous voulez, vous pouvez réellement jouer avec ça et mettre en œuvre cela afin que nous puissions réellement supprimer un autre Royaume-Uni ou bien même temps si nous avons plus d'une instance ici. Mais oui, bien sûr, à un moment donné, nous allons entrer dans ce problème où nous devons juste
fournir une sorte de semence. Et si nous avons plus d'une instance
leur fournissant la direction c et les doublons de début. Donc ouais, tu sais, sois conscient de
ça, ce problème existe juste. Et donc nous pouvons laisser une note, par exemple,
pour dire comme n'avoir qu'une seule instance ici. Et nous pouvons même le préciser à nouveau, nous pouvons dire l'instance un et nous pouvons dire, S'il vous plaît ne nous changez pas. Sinon, nous faisons du travail en double, quelque chose comme ça. Voir note ci-dessus. Et nous exécutons ceci une fois de plus juste pour nous assurer que cela fonctionne bien et mettre q celui-ci n'existe pas. Et si tout fonctionne correctement, mais, vous savez, juste être conscient de ça. Nous ne voulons pas avoir plus d'une instance ici parce que nous
itérons sur ces valeurs comme des valeurs d'entrée définies manuellement ici. Mais c'est debout pour une minute. Ouais, en regardant notre résultat et en regardant notre fonction principale, les choses sont en fait assez belles. La seule autre chose que nous pouvons faire, bien sûr, c'est si nous voulons obtenir un temps d'exécution approprié. Et nous avons mis ça en haut parce que sinon probablement commencer cette heure de cuivre après ça, mais nous appelons des travailleurs de jointure ici. Donc nous ne commencerons ça qu'une fois que tout le travail sera terminé. Donc, si vous voulez obtenir le bon moment, et bien sûr, nous devons mettre ceci ci-dessus comme ceci. Et nous pouvons également supprimer toutes ces importations inutilisées ici parce que toutes ces importations ont maintenant été transférées à notre lecteur jaune. Nous pouvons simplement économiser et rumeurs ou plus de temps pour nous assurer que cela fonctionne correctement. Mais maintenant c'est vraiment agréable parce que regardez à quel point notre fonction principale est devenue petite. C' est devenu si simple. Nous avons juste le pipe-line que nous voulons exploiter. Et puis nous avons juste notre pipeline exécuté ou qui s'occupe de tout. Et maintenant, si nous voulons faire plus de travail, alors, vous savez, nous pouvons prolonger cela. Nous pouvons soit, si nous avons plus d'URL qui suit la même structure que nous croyons que notre collaborateur wiki peut prendre soin de. Ensuite, vous savez, nous pouvons mettre plus de valeurs d'entrée ici. Nous pouvons étendre cela pour avoir des perspectives différentes. Habituellement, nous avons déjà parlé de peut-être sauver deux bases de données différentes ou quelque chose comme ça. Et bien sûr, vous savez, si nous créons un travailleur supplémentaire, nous devons nous assurer de définir ce travailleur aussi. Mais vraiment tout le travail acharné a été transféré au lecteur jaune. Cette chose prend en charge dynamiquement juste ce fichier de configuration YAML ici. Donc vraiment comme nous pouvons étendre cela autant que nous le voulons. Bien sûr, comme la seule chose que nous devons faire si nous ajoutons un type différent de travailleur, nous devons nous assurer que, vous savez, nous définissons la classe de travailleur et tout ce qui est comme ça et nous assurer que cela fonctionne correctement. Mais une fois que nous aurons cette classe de travailleurs disponible, nous pouvons la réutiliser. On peut agrandir nos pipelines, non ? Différents pipelines. Il y a beaucoup de choses cool que nous pouvons faire et tout ce que nous pouvons définir sur ce fichier YAML assez lisible et facilement maintenable. Il est donc si facile pour nous d'
augmenter et de réduire le nombre de travailleurs différents que nous voulons avoir. Si nous voyons, par exemple, o nos travailleurs Postgres un goulot d'étranglement. Parce que vraiment tout est juste une sorte d'attente pour être sauvegardé dans Postgres peut augmenter le nombre d'instances. Ou si ça va bien, nous pouvons réellement le laisser tel quel, ou même diminuer le nombre de thread n'est pas beaucoup. Nous voulons augmenter le nombre de grattoirs que nous avons. Il y a tellement de liberté pour nous d'accorder nos pipelines ici. Et tout cela a été transféré dans ce fichier YAML et notre code argent, nous allons juste prendre soin de tout ça dynamiquement.
13. Améliorer tous les travailleurs et ajouter un contrôle: Très bien, donc dans cette étape, nous allons nettoyer notre art que YAML Pipeline exécute ou un peu plus, juste en regardant notre fonction principale ici, vraiment ce que nous faisons c'est que nous appelons cette étape de pipeline de processus, où nous faisons tout comme charger le pipeline, puis les initialiser comme les files d'attente et les travailleurs. Et puis, bien sûr, appeler ce joint ici pour que, vous savez, nous attendions que tous ces travailleurs finissent. Et si nous regardons juste la façon dont cela, Voyons dans notre travailleur wiki par exemple ici. Donc, la façon dont nous gérons l'envoi fait en ce moment n'est pas idéale. Parce que ce qu'on fait c'est qu'on envoie ça, disons, 20 fois. qui est, eh bien, c'est un peu bizarre parce qu'imaginons que plusieurs de ces travailleurs courent en même temps. Donc, dans ce cas, si nous allons envoyer fait, mais l'un des autres travailleurs est en fait pas fait. Et nous envoyons fait plus que ce nombre de travailleurs en aval, alors ils vont tous lire et ils vont s'arrêter. Malgré peut-être un autre travailleur, vous savez, toujours mettre des valeurs dans cette file d'attente plus tard. Maintenant, bien sûr, dans ce cas, eh bien, nous pouvons avoir cela pour le travailleur Yahoo Finance, par
exemple, car le travail wiki ne sont actuellement pas tellement parce que nous limitons les instances ici à un. Puisque nous devons nous assurer que nous fournissons essentiellement cette semence non doublons. Mais ça ne peut pas arriver avec l'employé de Yahoo Finance. Si l'un d'eux se termine juste avant l'autre, et qu'il met juste tout
là-dedans et alors l'autre est en fait toujours en cours d'exécution et
en met un peu pour être utilisé alors que tous les travailleurs en aval vont lire ceci et en fait, ils n'obtiendront pas les valeurs finales qui ne sont pas dans ce cube. Donc, dans cette étape, optimisons un peu cela. Et prenons cela en envoyant le signal de nos travailleurs et nous allons le déplacer dans notre principal travailleur. Essentiellement, nous ne sommes pas actuellement un travailleur, est juste un peu comme une classe qui nous aide à exécuter le pipeline. Mais en fait, nous allons importer le thread. Et nous allons en faire un fil 2. Nous allons donc en faire notre principal travailleur. Et ce que nous allons faire maintenant, c'est que nous sommes, bien
sûr, nous devons ajouter l'étape de course. Ici. Nous allons être pris en charge du suivi des progrès et de l'envoi des commandes effectuées une fois que tout est fait. Donc, nous allons aussi enlever qui se joignent aux travailleurs. Parce que la première étape que nous allons faire une fois ce processus démarré est que nous allons réellement être en cours d'exécution de l'étape de pipeline de processus. Donc, si nous avons rejoint les travailleurs ici, alors tout sera bloqué jusqu'à ce que nous atteignions ce point. Donc, bien sûr, nous ne pouvons pas appeler les travailleurs de jointure et en fait nous n'en avons même pas besoin parce que aussi ici nous allons avoir comme une boucle infinie qui va fondamentalement juste prendre soin de tout, peut prendre soin de toute la surveillance, etc, mur, tout le reste est actif. Et pour cela, bien sûr, nous devons aussi juste commencer notre fil pour que, vous savez, commence à courir. Ok, alors qu'est-ce qu'on va faire ici ? Eh bien, vraiment ce que nous voulons faire, c'est que nous voulons savoir pour chaque travailleur, tout d'
abord, combien, comme q envoie deux, et aussi combien de travailleurs sont encore en vie. Et puis ce que nous voulons être en mesure de faire est une fois que tous les travailleurs ne sont plus en vie, nous voulons envoyer fait à toutes les files d'attente de sortie qu'il envoie. Donc, par exemple, si nous avons trois QS de sortie ici et que celui-ci est fait, alors nous voulons envoyer fait à toutes ces files d'attente de sortie. Et idéalement, le nombre de fois que nous avons envoyé fait
dépend également du nombre d'instances réellement consommées à partir de cette file d'attente. Donc, nous allons avoir une chose distincte qui nous aide juste à suivre le nombre d'instances, nombre de travailleurs consomment dans chaque file d'attente. Alors allons-y et mettons-en place ça. Et nous allons en fait faire une partie de nos travailleurs initialisent. Mais d'abord, nous allons réellement mettre ceci dans notre méthode initialisée de fonction ici. Je vais écrire quelques trucs et expliquer ce qui se passait avec eux. Nous pouvons récapituler une fois qu'il sera sorti, car une fois que nous l'aurons écrit, il sera
évidemment un peu plus facile de comprendre la logique
plutôt que de l'expliquer dans un sens plus abstrait. Nous allons donc avoir ici des consommateurs Cube. Et nous allons aussi noter les indices en aval. Donc, la variable Q consommateurs va essentiellement dire, pour ce symbole Q, c'est le nombre de travailleurs consomment de cette file d'attente. Et le cuz en aval va toujours
être le travailleur et ce que c'est aussi sensé. Ce sont donc les deux attributs supplémentaires que nous ajoutons ici afin que nous puissions garder une trace de ces informations car nous en aurons besoin plus tard. Alors maintenant, quand nous initialisons nos travailleurs, nous devons garder une trace de, eh bien, tout d'
abord, quels indices est-ce juste ? Deux. Donc, nous avons la sortie QS. Bien sûr. Ici. Donc nous allons avoir, nous allons ajouter ici dans nos repères en aval. Pour ce travailleur va écrire deux files d'attente de sortie oui. Maintenant, notez que nous prenons les noms de la sortie QS ici afin que nous puissions les référencer plus tard ici. Mais nous n'avons pas vraiment besoin de prendre l'instance de la file d'attente. On peut juste suivre le nom ici. Et puis nous voulons aussi savoir ce que Q est consommé. Donc, si nous avons une file d'attente d'entrée ici, et alors nous pouvons dire, si l'entrée q n'est pas nulle, alors nous voulons noter ici ce Q comme étant consommé par autant de travailleurs, non ? Donc, en fonction du nombre d'instances que nous avons ici, et c'est combien de travailleurs vont être consommés à partir de la file d'attente. Maintenant, avec ça, nous avons une sorte d'hypothèse implicite que chaque file d'attente va être un peu pour un travailleur. Donc, par exemple, si nous avons un second travailleur qui veut utiliser les résultats d'ici, il ne va pas lire à partir de cette file d'attente parce que cela répartit fondamentalement nos valeurs sur deux travailleurs séparés qui vont être faire deux choses distinctes. Si vous voulez stocker ces données brutes quelque part, alors nous devons avoir un Q de sortie séparé, afin que nous ne manquions aucune valeur que fondamentalement les deux travailleurs, un d'eux sera le traitement et l'autre qui va juste stocker les valeurs brutes. Ils ne veulent pas lire à partir du même cube parce qu'ils ressemblent à partager les données et une des parties de celui-ci est sauvegardée et d'autres parties du traitement. Mais nous voulons vraiment chaque étape de ce pipeline traite l'ensemble des données. Donc, si nous avons besoin de ce jeu de données 2, alors nous devons ajouter un autre Q de sortie ici pour nous assurer que nous pouvons utiliser le jeu de données complet. Et donc avec ceci et ce que nous écrivons ici, encore une fois, nous supposons que chaque cu est spécifique à un travailleur. Donc, si nous consommons du symbole Q ici, alors nous ne pouvons pas consommer à partir du symbole Q avec un travailleur séparé ailleurs, parce que sinon, ils vont diviser
les données ici parce qu'ils vont tous les prendre dehors. Donc c'est une sorte d'hypothèse implicite que nous faisons ici. D' accord ? Mais maintenant, nous avons, vous savez, maintenant nous savons à quel travailleur Q chaque travailleur écrit, et aussi quel q, combien de travailleurs consomment de chaque file d'attente. Bon, donc nous avons le processus Run ici. Donc maintenant, ce que nous voulons faire est fondamentalement, et nous pouvons régler ça à un intervalle. Donc, je vais aussi importer du temps parce que cela nous permet d'avoir une fonction de sommeil à la fin. Alors peut-être qu'on dort cinq secondes à la fin. Alors que nous n'aimons pas le faire continuellement, mais fondamentalement le faire à intervalles. Donc nous allons faire notre surveillance. Donc, ce que nous voulons faire est fondamentalement pour chaque travailleur et pour chaque thread et chaque travailleur, nous voulons juste vérifier s'il est toujours en cours d'exécution. Alors qu'est-ce que ça veut dire ? Si nous regardons notre travailleur Yahoo Finance, par exemple, une fois que nous sortons de cette boucle ici, et fondamentalement cette méthode arrive à sa fin, alors le travailleur n'est plus en cours d'exécution. À ce moment-là, l'ouvrier n'est plus vivant. Et donc fondamentalement, nous voulons être à la recherche des points lorsque, par exemple, ce travailleur sort de sa boucle d'exécution ou termine sa méthode d'exécution ici. À ce moment-là, il n'est plus vivant. À ce moment-là, nous savons, d'accord, cet ouvrier a fini. Ainsi, nous pouvons commencer à envoyer et faire aux consommateurs en aval. Bien sûr, si nous avons plus d'instances que nous devons nous assurer que ce n'est pas seulement une instance qui s'est terminée, mais que c'est chaque instance qui s'est terminée. Donc ce qu'on va faire, c'est dire pour l'
ouvrier, le nom de l'ouvrier, et maintenant on veut juste prendre nos ouvriers. Alors, en boucle sur nos ouvriers. Et ici, nous allons garder une trace de la vie totale des threads de travail. Donc, parce que chacun de nos travailleurs peut avoir plusieurs threads, nous voulons juste garder une trace du nombre total de threads en cours d'exécution. Donc on va boucler de chaque côté. Nous allons dire pour le thread de travail, comme ici, en boucle sur chaque thread que nous gardons une trace ici. Alors, comment peut-on vérifier si c'est lifo ? En fait, c'est relativement facile. Tout ce que nous avons à faire est que nous devons prendre notre fil et nous pouvons simplement utiliser cette méthode est vivante. Et cela nous dira si l'ouvrier est encore en vie ou pas. Donc on peut dire si un travailleur est en vie. Ensuite, nous voulons juste incrémenter ça d'un. Donc, fondamentalement, pour chaque travailleur vivant que nous avons, alors nous allons l'incrémenter d'un. Et donc à l'avant, si nous n'avons aucun de ces travailleurs en vie, donc si tous les fils sont terminés, maintenant nous pouvons commencer à prendre les signaux en aval d'ici, et nous pouvons commencer à envoyer fait à elle. Donc nous pouvons dire, tout ce qu'il nous faut pour obtenir les indices en aval. Et quatre ici, on doit vérifier d'abord, sinon aucun, parce qu'on ne peut pas avoir d'affaires. Par exemple, notre collaborateur Postgres n'a pas de files d'attente de sortie. Donc nous voulons nous assurer que les indices en aval que nous avons, qu'ils existent. Donc, si des indices de réduction ou pas, alors nous voulons, pour Q en aval dans les indices en aval que nous avons pour chaque travailleur. Donc ce qu'on fait, c'est qu'on bouclait, Voici un fichier YAML. Nous sommes en boucle sur chacun de ces QS de sortie ici. Depuis ce sera le cas, ce que nous gardons une trace dans cette variable Cuz en aval, c'est que nous gardons une trace de toutes les files d'attente de sortie. Nous pouvons donc appeler cela pour Q en aval. Nous pouvons appeler ce Q de sortie pour être plus cohérent avec une syntaxe que nous avons ici. Donc, nous pouvons l'utiliser pour acheminer pour chaque sortie Q et ici. Ensuite, nous voulons avoir un nombre de consommateurs. Donc maintenant, nous voulons savoir pour chaque sortie Q, combien de threads sont en train de lire à partir d'ici. Eh bien, nous suivons ça ici. Donc, nous savons pour chaque q combien de threads ou la lecture de celui-ci. Donc, le nombre de consommateurs ici. Nous pouvons juste lire ce dictionnaire que nous avons mis en place plus tôt ici. Et puis nous pouvons dire pour moi dans la gamme nombre de consommateurs. Et maintenant pour chacun d'entre eux, nous pouvons envoyer fait à ce Q. Donc, nous devons réellement obtenir cette FAQ. Donc, et je vais, je vais en quelque sorte résumer dans une seconde. Mais d'abord, nous allons juste écrire ça pour que nous ayons, vous savez, tout ce qu'il faut ici. Donc nous allons prendre notre Q. de sortie et tout comme nous l'avons fait ici, nous allons mettre terminé. D'accord ? D' accord ? Et puis la dernière chose que nous pouvons peut-être faire, si nous n'avons plus de ces menaces vivantes, alors nous pouvons réellement supprimer, nous pouvons retirer ce genre de travailleur de notre suivi afin que nous n'ayons plus besoin d'une trace. Et maintenant, ok, alors comment allons-nous
sortir de cette boucle infinie pendant que nous voulons aussi garder une trace du total des travailleurs vivants. Et fondamentalement, nous pouvons probablement le faire ici parce que nous voulons garder une trace de cela à chaque itération. Donc chaque fois que nous traversons et pour chacun des travailleurs, nous voulons savoir, vous savez, combien de travailleurs et total vivant. Nous allons passer en revue tous les ouvriers. Et puis ici, nous pouvons réellement dire, eh bien, nous pouvons soit faire tout en étant vrai, et ensuite vous pouvez dire ici, si le total des travailleurs vit est égal à 0, alors nous pouvons en sortir. Ou nous pouvons dire, tandis que les réservations totales en vie parce que non égal à 0. Mais bien sûr, nous devons le définir ici et crier. Donc, dans ce cas, l'
une ou l'autre de ces options sont en quelque sorte ok. Et ça dépend vraiment de ce que tu veux aller avec, je suppose ici. Eh bien, puisque nous avons ça maintenant et nous allons juste aller avec ça. C' est un peu gênant d'avoir comme cette duplication ici. Dans ce cas, je pourrais aussi le mettre vers l'arrière afin que nous recomptions fondamentalement, réinitialisions le compteur à la toute fin. Mais vraiment, ça ne va pas bien. Nous ne voulons pas vraiment réinitialiser le compteur à la toute fin car alors nous serions en train de sortir de cette boucle. Donc oui, on veut l'avoir en haut. Ok, alors passons juste en revue ce que nous avons. Et en fait, la première chose que je vais faire est que je vais juste commenter tous ces trucs parce que nous ne voulons plus que nos threads, bien
sûr, envoyer ces signaux faits. Mais au lieu de cela, nous voulons que notre pipeline principal en soit responsable. Alors qu'est-ce qu'on vient de faire ? Eh bien, tout d'abord, nous avons retiré les travailleurs de notre pipeline de processus. Parce que si nous faisons cela, alors fondamentalement cette étape va être bloquée et nous ne voulons pas cela. Donc, nous avons retiré ça de cette étape ici. Et dans nos collaborateurs initialisés, nous avons ajouté deux attributs supplémentaires que nous suivons. Chacun d'eux a un dictionnaire. Donc, pour chaque travailleur, pour suivre ce Q, ils en envoient deux. Donc, nous suivons leur sortie Q. Et pour chaque q, nous sommes aussi, sont pour chaque travailleur, nous suivons également comme q ils lisent et combien d'instances lisent dans la file d'attente. Encore une fois, en supposant que chaque repère est spécifique à un travailleur. Nous ne pouvons donc pas réutiliser le symbole Q, par exemple. Ici, comme ça ne fonctionne pas parce qu'alors ils vont
diffuser les données qui viennent d'ici. Et cela va en lire une partie, et cela va en lire une partie. Mais ni l'un ni l'autre ne va obtenir le jeu de données
complet. Donc on ne peut pas faire ça. Donc, avec cette hypothèse, nous disons essentiellement, Ok, chaque type de travailleur et nous pouvons augmenter le nombre d'instances ici toujours pas de problème. Mais chaque type de travailleur que nous avons ici a une file d'attente spécifique qui lui est associée afin que nous sachions maintenant, ok, pour chaque q, nous savons que c'est le nombre d'instances
qui en consomment, que nous pouvons voir ici. Ok, donc maintenant nous gardons juste une trace de ces statistiques Q. Donc, plus tard, lorsque nous appelons cette méthode d'exécution ou, puis les prochaines étapes de cette méthode d'exécution et que vous
utilisez l'exécution parce que nous avons transformé cela en une classe de thread. Nous commençons maintenant une boucle qui va essentiellement garder une trace de ce genre de surveillance pour nous dans une main. Nous allons réellement mettre en œuvre la surveillance dans une seconde. Mais aussi il va prendre soin de l'envoi fait aux files d'attente de sortie. Ce qui est encore important parce que si nous le faisons ici, qu'une menace pourrait finir, je pourrais commencer à envoyer fait, et un autre thread pourrait être en cours d'exécution, et il sera en fait ajouter des valeurs après que le fait ici a été envoyé. Mais, tu sais, avec ça, on envoie 20 messages faits. Ensuite, les consommateurs en aval vont tous s' arrêter parce qu'ils vont obtenir la valeur w1. Et puis ils vont être des messages dans la file d'attente qui seront laissés non lus. Donc, nous voulons éviter cela et nous ne voulons envoyer fait qu'une fois que chaque travailleur a terminé. Donc, la façon dont nous faisons ça c'est que nous faisons une boucle sur chaque travailleur que nous avons. Et pour chaque travailleur, nous allons chaque thread et nous vérifions simplement si ce thread est vivant ou non. Et maintenant ce que cela signifie est qu'un thread n'est plus vivant s'il termine sa méthode d'exécution ici. Donc, fondamentalement, s'il sort de cette boucle de course, ce point de thread n'est plus vivant. Et ça ne déclencherait pas. Mais s'il est encore vivant, cela signifie
qu'il est toujours dans cette boucle de course ici. Et donc nous gardons juste une trace du nombre total de threads de travail qui sont vivants. Et si aucun des threads n'est vivant, cela signifie que chaque travailleur a terminé. C' est cassé si c'est en boucle. Alors nous savons, ok, maintenant nous voulons envoyer fait à tous les indices qu'il écrit. Donc, nous devons faire une boucle sur chaque sortie Q, m pour chaque Q de sortie unique, nous devons envoyer fait un certain nombre de fois fonction du travailleur qui lit à partir de cette file d'attente, qui est celui-ci. Combien d'instances cette barre ? Ainsi, par exemple, dans ce cas, nous avons six instances lisant le téléchargement Postgres. Et donc nous voulons nous assurer que nous envoyons fait au moins six fois afin que chaque instance ici lit le message fait. Et c'est la logique que nous avons mise en œuvre ici. Et puis, à la toute fin, on retire ce travailleur du suivi pour qu'une fois que c'est fait, on n'a plus vraiment besoin de faire la même chose. Nous savons, comme une fois que nous avons envoyé tout ça ici, alors, vous savez que l'ouvrier a complètement fini. On n'a plus besoin de le suivre. Il y a donc une autre chose que je veux juste ajouter ici, qui sera les statistiques des travailleurs. Et ce que je veux faire ici, c'est juste ajouter le nom de l'ouvrier, ainsi que combien de travailleurs sont en vie. Et puis à la toute fin ici, je voulais imprimer des pas de travail automatique. Maintenant, c'est juste une sorte de surveillance pour nous afin que nous puissions réellement voir ce qui se passe. Et ici, dans notre thread principal, j'ai en quelque sorte remplacé ce pipeline de processus était juste l'étape de départ afin que nous commencions réellement cette méthode d'exécution ici. D' accord, donc vous n'êtes pas seulement activer mon environnement virtuel. Et puis nous allons de l'avant et courir et réellement besoin d'activer Postgres à. Parce que pour l'instant mon instance Postgres ou mon serveur Postgres ne fonctionne pas localement, il suffit
donc de vous assurer que cela démarre. Alors voyons, on y va. Bon, alors allons-y et lançons ça. Ok, on a une erreur ici. La méthode d'initialisation n'est pas appelée. Nous voulons donc
initialiser la menace bien sûr aussi. Bon, essayons encore une fois. Ok, donc ça marche à nouveau. Donc, pour cela actuellement, eh bien, tout d'abord, nous avons encore cette extraction, ce qui est juste parce que nous ne les appelons pas des méthodes de jointure. Donc c'est un peu la même chose que nous avions avant qu'il pleut parce que nous n'appelons pas rejoindre ici. Il saute essentiellement pour entendre presque immédiatement. Mais l'autre chose est, il semble que nous n'imprimerons pas encore les statistiques ici. Alors je le ferai, bien sûr. C' est une erreur ici. Si nous mettons ça à 0 ici, alors bien sûr, nous n'entrerons même pas dans cette boucle. Laisse-moi réparer ça. Et juste ici, dis que c'était un peu mon bouton. Si nous définissons cela sur 0, si ici, et si nous disons,
alors que ce n'est pas 0, eh bien, c'est déjà 0, donc nous n'allons même pas entrer dans cette boucle. Alors, enlevez ça. Mais il y a une autre chose que je voulais faire, c'est
d'avoir une liste de travailleurs que nous devrions supprimer. Et plutôt que de le supprimer immédiatement ici, je veux réellement ajouter ce nom de travailleur, puis le supprimer plus tard. Donc, je veux être en mesure d'entendre peut-être pour travailleur et de supprimer ici, je voulais le diriger. La raison en est que si nous supprimons ici, nous continuons à itérer, comme si nous étions toujours en boucle sur cela. Et donc pour la suppression pendant que nous bouclons, alors Python va être contrarié contre nous. Donc on ne veut pas faire ça. Nous ne voulons supprimer qu'une fois la boucle terminée , c'est pourquoi je le garde comme ça. Essayons encore une fois. Ok, on y va. Maintenant, nous voyons nos statistiques de travailleurs. Donc, nous pouvons voir notre collaborateur wiki ici terminé. Et on a aussi remarqué qu'on montait ici. Nous voyons en fait neuf travailleurs ici, ce qui est bien sûr faux. Ce n'est pas erroné notre surveillance, car ici nous voulons montrer le total des threads de travail vivants, pas le nombre total de réplicas vivants, ce qui est en quelque sorte l'agréger. Maintenant quelque chose qui devrait se produire mais qui ne se passe pas réellement. Et je vais juste prendre ce temps de sommeil ici juste pour m'assurer que ce n'est pas un problème. Mais nous pouvons voir dans nos journaux que nos travailleurs
atteignent des délais d'attente et qu'ils ne sont pas arrêtés par nos signaux d'arrêt. Alors bien sûr qu'on ne veut pas ça. Nous voulons nous assurer que vos délais d'expiration sont atteints atomes. Donc on ne veut pas ça. Nous voulons nous assurer que, vous savez, nos travailleurs s'arrêtent avec la méthode que nous faisons ici. Donc, jeter un oeil à nouveau à notre boucle, eh bien, cela devrait être n'est pas nul. Parce que nous voulons y aller si nous avons réellement des travailleurs en aval. Allons-y et essayons encore une fois. Et on y va. Donc maintenant, nous résolvons le problème que nous avions plus tôt, qui était que nous n'envoyions pas fait d'ici, mais plutôt nous arrivons à des délais d'attente. Et bien sûr, nous pouvons voir que c'était génial d'avoir ces délais d'attente parce que ça aide à combattre certains des bogues réels que nous avions ici. Nous n'étions pas coincés dans une boucle infinie. Mais oui, donc nous avons un peu fini cette partie, qui est en fait extrêmement sympa parce que maintenant nous ne sommes plus envoyer fait d'ici. Alors allons de l'avant et supprimons cela aussi. Et de cette façon quand nous avons plusieurs instances, alors ce n'est pas si le premier se termine et qu'il envoie fait, alors, vous savez, tout le reste en aval va s'arrêter. Et même si nous envoyons fait une seule fois, alors nous sommes allés à des problèmes comme ce qui se passe si le nombre de travailleurs en aval n'est pas égal au nombre de travailleurs que nous avons actuellement. Si nous avons plus de travailleurs en aval et qu'ils ne vont pas
finir et ils atteindront des délais d'attente. Et même s'ils le font, alors ils s'arrêteront avant que tous les travailleurs ne
cessent, ce qui signifie que notre débit va baisser. Donc l'avoir de cette façon, c'est beaucoup plus agréable parce que maintenant nous envoyons fait. Une fois que nous avons su tout
cela, tous ces travailleurs ont fini. Maintenant, il y a encore une chose courte que je voulais vous montrer et je sais que nous avons un peu de temps ici, mais en fait, nous ne pouvons pas exécuter cela parce que malheureusement cela ne fonctionne pas sur Mac, mais cela fonctionne sur Linux. Donc, nous gardons une trace des statistiques de nos travailleurs ici. Et nous n'aimerions probablement pas faire une chose similaire pour q dit que c'est
juste, juste comprendre combien de données sont réellement dans nos indices. Maintenant, il y a cette méthode si on regarde la file d'attente. Donc encore une fois, ce ne sera pas comme écrire le truc complet parce que ça ne va pas courir de toute façon. Mais nous pouvons dire comme pour Q dans, dans notre QRS et ensuite juste avoir cette file d'attente. Et puis ici, nous pouvons regarder la taille de la file d'attente. Donc, c'est encore une fois, quelque chose qui n'est pas tout disponible, malheureusement sur Mac, mais sous Linux, c'est quelque chose que vous pouvez réellement faire, c'est que vous pouvez obtenir les tailles de file d'attente. Maintenant, euh, et c'est juste vraiment sympa parce que, en gros, vous savez, vous êtes capable de surveiller combien il y a dans chaque file d'attente. Et avec ça, alors vous pouvez dire, Oh, ok, vous connaissez tant de travailleurs ou ont, mais je peux vraiment voir comme, oh, ce Q super plein. Donc, je vais en fait ajouter plus d'instances là-bas et peut-être que je prends des travailleurs ailleurs où la taille de la file d'attente est toujours 0. Donc, avoir cet outil de surveillance Q est aussi vraiment agréable. Et bien sûr, nous pouvons le mettre comme aussi comme oh, Q commence comme ça. Et là, nous pouvons, vous savez, comme nous l'avons fait avant, plutôt que de simplement imprimer ça. Vous pouvez ajouter ceci ici et ensuite nous pouvons imprimer comme des points accusés. Maintenant, malheureusement, et vous verrez si je lance ceci,
cela va provoquer une erreur car fondamentalement, cela n'est pas implémenté sur Mac doucement. Donc, cela fonctionnerait sur un système Linux, mais malheureusement il ne fonctionne pas sur Mac. Donc oui, on ne peut pas l'utiliser ici. Mais la plupart du temps, si vous aimez utiliser des choses en production et qu'il va probablement fonctionner sur un système Linux car il sera déployé comme une image Docker ou quelque chose comme ça. Donc, dans ces cas, vous êtes en mesure de laisser ce morceau de code dedans. Vous pourrez également surveiller les statistiques des files d'attente. Et avec cela, vous serez en mesure d'obtenir plus d'informations en parcourant les journaux. Augmentez le nombre d'instances postgres. Je réduit le nombre d'instances peut-être parce que c'est toujours 0. Et donc il ne sert à rien d'avoir autant d'instances si notre q est toujours 0. Et donc oui, sans espérer que vous serez en mesure de prendre ces informations que vous obtenez et de prendre des décisions plus intelligentes sur la façon dont vous êtes, nombre d'instances que vous attribuez réellement à chacun des différents travailleurs que vous avez ici. Mais oui, ce genre de genre nous amène à la fin de cette optimisation ici. Et nous sommes en fait très, très près de finir ça. Donc, la seule chose qui reste, qui est ce que nous allons couvrir dans la prochaine vidéo, est fondamentalement que nous voulons prendre certaines des définitions que nous avons, particulier comme l'emplacement du pipeline ou quelque chose comme ça. Et nous le voulons, ou je veux le mettre dans une variable d'environnement. Mais encore une fois, nous en parlerons dans la prochaine leçon.
14. Nettoyage du programme final: Très bien, donc dans cette leçon, nous allons juste faire un nettoyage rapide, essentiellement aller et simplement déplacer cela vers une variable d'environnement, mais aussi avoir comme une variable d'environnement locale que nous pouvons utiliser pour les tests réels et autres comme ça. Donc juste que tout cela devient un peu plus gratuit en fonction de chaque fois que nous voulons démarrer le programme, nous pouvons en quelque sorte le définir dans ce sens. Donc vous êtes, bien sûr, la première chose que nous allons faire est dire que cet environnement est, je vais juste appeler ça notre emplacement de pipeline. Et ici, nous avons également besoin d'importer le système d'exploitation. Maintenant, ce que je vais faire, c'est que je vais créer un fichier ENV dot, qui va être nos variables d'environnement. Et je suis en fait, laissez-moi renommer ça parce que je vais appeler cette pensée et locale. Donc, cela va être comme nos variables d'environnement locales. Cela signifie que si nous voulons avoir plus tard des variables d'environnement de mise en scène et de production, alors nous pouvons changer chacune de ces n en fonction de ce que nous voulons tester. On peut utiliser différentes choses. Je suis principalement que vous voulez tester probablement sur local et la mise en scène. Nous allons donc définir nos variables d'environnement ici. Et on va juste, juste prendre ça ici. Donc, ce que cet expert nous permet de faire en une seconde lorsque nous utilisons cette commande source, c'est que nous sommes capables, pendant que nous sommes en mesure de source le fichier d'environnement. Et puis ce que cela signifie est que cette exportation aura juste comme définir ces variables d'environnement dans notre terminal ici. De cette façon, nous pouvons simplement, vous savez, les
faire définir dans notre terminal,
dans notre instance de terminal en cours d'exécution. Et puis quand nous l'exécutons, nous allons utiliser ces variables d'environnement. Donc, nous ajoutons l'emplacement du pipeline, mais en fait, passons par un autre travailleur parce que dans notre travailleur Postgres, nous utilisons également des variables d'environnement. Donc, nous avons un utilisateur Postgres, qui va juste être une chaîne vide. Nous avons le mot de passe Postgres, qui va également être une chaîne vide, et le cas Mac dans le cas Windows ici vous allez avoir des valeurs définies ici. L' hôte Postgres sera notre hôte local. Et la base de données Postgres sera ce que nous avons ici. Maintenant, dans ce cas, je vais en fait retirer ça d'ici. De cette façon, nous ne l'avons défini qu'ici. Autant que je sache, cette source d'environnement et cette syntaxe est spécifique aux systèmes Linux et Mac. Mais vous savez, si vous êtes sur un Windows, vous pouvez toujours avoir la syntaxe similaire à nouveau, comme nous avons parlé de la dernière leçon. En fait, vous allez être, vous savez, si vous le faites ou si quelqu'un d'autre vous aide à le déployer quelque part, que cela sera généralement toujours exécuté contrairement à un système basé sur Linux. Donc, vous savez, vous serez en mesure d'utiliser cet environnement. Et la syntaxe de l'environnement fonctionnerait aussi sur un Windows. Mais spécifiquement comme cette syntaxe d'exploitation de cette façon, je suis à peu près sûr est exactement comme Linux et Mac spécifique. Mais ne vous inquiétez pas parce que c'est juste un peu comme les dernières étapes du nettoyage. Et encore une fois, si vous l'exécutez ailleurs, vous pouvez réellement passer ces variables d'environnement. Et donc nous avons nos variables d'environnement ici. Et nous avons ici. Ici, nous devons dire, si nous n'avons pas d'emplacement de pipeline, alors nous allons essentiellement sortir avec un code de sortie. Les ensembles ont échoué et nous allons dire, je suis l'emplacement du pipeline non défini. Et puis si nous voulons avoir le temps d'extraction de votre tube, parce que notre exécuteur principal, nos exécuteurs YAML I en fait aussi une menace maintenant, eh bien nous pourrions faire est bien, nous pourrions appeler ça comme montrer des travailleurs. Mais nous savons vraiment qu'en regardant cela, notre fil principal ici, ou notre fil jaune ouvrier, ne sortira de l'anode que lorsque tous les travailleurs et Saturne auront terminé. Donc seulement une fois que tous les travailleurs à l'intérieur seront terminés on va vraiment aimer sortir d'ici de toute façon ? Donc, vraiment, nous pouvons aussi simplement l'
appeler, appeler la jointure ici si nous voulons obtenir ce temps d'extraction. Alors allons de l'avant et essayons simplement comment cela fonctionne. Nous allons activer nos variables d'environnement locales afin que nous puissions voir si je veux imprimer cette variable. Ok, donc maintenant c'est défini. Et cet écho n'est qu'une commande de terminal que nous pouvons utiliser. Et ce symbole de dollar ici
signifie essentiellement que nous voulons imprimer l'accès à la valeur d'une variable, que nous avons définie ici. Donc, c'est très similaire, tout comme la définition des variables en Python est juste, la syntaxe est un peu différente pour comme le terminal, mais c'est essentiellement l'impression de la valeur de l'emplacement du pipeline. Et ici, nous définissons la variable d'emplacement du pipeline pour être de cette valeur. Bon, alors essayons de réexécuter notre fonction
principale et de nous assurer que tout fonctionne correctement. Et après avoir fait ces changements, ce qui semble être le cas. D' accord, et donc nous avons aussi le temps d'extraction approprié. Et puis une autre chose que je veux faire est, je veux dire, nous ne voulons probablement pas imprimer tout ça tout le temps. Tu sais, c'est plus à des fins de test pendant qu'on l'avait. Donc, nous pouvons simplement supprimer cette impression et je l'exécute une fois de plus juste pour m'assurer que la sortie est propre aussi. Donc tout a l'air vraiment propre. Et oui, on y va. Ce genre de comme nous amène pourrait également supprimer cela fondamentalement toute chose commenté inutile. Et oui, ce genre de nous amène à la fin de tout
ce tutoriel de threading où nous avons construit et vous savez, tout
ce programme de threading à faire comme la mise au rebut et téléchargement de
bases de données et tout ça juste pour se déplacer. Les problèmes sont comme les délais d'attente que nous avons connus à l'époque étaient les périodes d'attente associées à la communication réseau. J' espère donc que cela vous a plu, vous avez beaucoup appris et que vous êtes en mesure de transférer une partie de cela à vos propres projets ou à votre propre travail. Et encore une fois, utilisez cela spécifiquement dans les cas où les facteurs limitatifs sont les temps de communication réseau. Encore une fois, le threading n'est pas optimal pour optimiser charges de travail lourdes de
calcul parce que nous n'utilisons plus de CPU similaire. C' est juste quand nous attendons que les réseaux répondent. Nous avons une communication réseau que d'autres threads peuvent continuer à fonctionner tandis que les autres threads attendent juste une réponse d'un autre endroit sur le réseau. Encore une fois, vous savez, un excellent travail pour compléter cette section du cours. J' espère que ça vous a plu. J' espère que vous avez beaucoup appris.
15. Verrouillage: Bon, alors maintenant que nous avons construit ces applications de filetage assez cool et quelque chose que nous avons beaucoup utilisé à l'intérieur était en fait tous ces indices, qui si vous vous souvenez au tout début quand nous parlions du QRS. Voyons où les initialiser ici. Nous avons donc parlé d'être thread-safe. Alors qu'est-ce que ça veut dire exactement ? Et cette leçon, j'ai rapidement voulu passer sur le verrouillage et quelque chose connu sous conditions de course afin que vous puissiez comprendre certaines choses dont vous pourriez avoir besoin de se méfier lorsque vous faites le filetage. Donc je vais créer un nouveau fichier ici. Je vais appeler « pas verrouiller ». Et ce que nous allons faire ici, c'est que nous allons juste importer des threading. Et nous allons avoir une petite fonction. Nous allons avoir un compteur global qui sera réglé sur 0. Et nous allons avoir une petite fonction appelée incrément. Et ça va prendre notre compteur et nous allons juste avoir une boucle ici. Nous allons dire pour moi à portée, puis commencer par 10. J' utilise les pouvoirs de 10 ici, sorte que sur off pour écrire dix, puis un 100 et 1000. Donc je vais utiliser les pouvoirs de 10 juste pour rendre ça un peu plus facile et tu verras pourquoi dans une seconde. Donc, nous allons avoir une boucle ici qui fait actuellement juste dix itérations. Et pendant chaque itération, il va implémenter un compteur par un. Maintenant, ici, j'appelle juste la variable globale au cas où vous ne l'avez pas vu auparavant, c'est que nous modifions cette valeur, nous devons en fait nous assurer que nous appelons la variable globale en haut ici, puisque nous n'y accédons pas seulement, mais nous sommes en train de le modifier. Donc maintenant ce que je vais faire, c'est que je vais créer quatre threads. Je vais dire que pour moi, au quatrième
rang, on va créer un fil. Et notre cible sera cette fonction d'accroissement. Et puis nous allons juste les ajouter et ensuite nous allons les commencer tous. Donc, on va dire « T point start ». Et puis nous allons également appeler la méthode join pour nous assurer que nous attendons jusqu'à ce qu'ils soient tous terminés. Et à la toute fin, nous allons imprimer notre contre-valeur. Programme donc assez simple. Vraiment ce que nous faisons, c'est que nous avons une variable globale ici, compteur initialisé à sigma. Et puis nous avons juste une fonction qui va prendre cette variable globale
qui va incrémentée dix fois. Et nous allons exécuter ça sur quatre threads. Donc, chaque thread va appeler cette fonction. Donc, au total, nous devrions avoir une valeur de 40 ici. Puisque nous avons quatre threads, chaque thread appelle la fonction. Chaque appel de fonction va incrémenter cette valeur de 10, donc 4 fois 10, ce qui va être 40. Alors allons de l'avant et lançons ça. Très bien, car ça a l'air plutôt bien. Essayons donc d'incrémenter ce nombre ici. Au lieu de faire dix, faisons-le 1000. Donc ça va être de 10 à 3. D' accord ? Et allons de l'avant et lançons ça. Ok, quatre mille, c'est exactement ce que nous attendons. Essayez d'incrémenter ceci une fois de plus. Au lieu de faire 1000 opérations, nous allons en faire un million. Donc, ce que nous prévoyons voir ici sera de 4 millions. Depuis chaque valeur, nous allons juste incrémenter un million de fois et nous allons le faire sur quatre threads. Alors allons de l'avant et lançons ça. Oh, eh bien c'est bizarre. Pourquoi on a ça et pas 4 millions ? Donc, ce que nous avons rencontré ici est quelque chose appelé une condition de course, où fondamentalement nous avons une variable partagée, qui est ce que nous avons ici. Et plusieurs entités différentes essaient d'y accéder en même temps. Donc, ce qui se passe à un moment donné, c'est que nous avons notre compteur, qui est égal à n'importe quelle valeur x. et ensuite nous avons un thread. Un fil le lit et il voit oh, compteurs x. et puis il va essayer de l'incrémenter par la suite. Mais en même temps, nous avons un autre thread, disons thread T2, qui voit aussi compteur est égal à x. alors ce qui se passe est quand nous avons thread un dit compteur est égal à compteur plus un. Donc, cela signifie qu'un compteur d'essence est égal à x plus 1. Et puis nous avons aussi du fil à faire la même chose. Donc, nous avons dans ce cas est le résultat que nous obtenons est en fait compteur est égal à x plus 1, même si nous avons eu deux threads y accéder. Et la raison pour laquelle cela arrive est parce que parfois ces valeurs fondamentalement, ils voient la même chose et ensuite ils appellent leurs opérations, mais ils ne l'ont pas lu séquentiellement. Donc ils n'ont pas lu l'un après l'autre. Il n'a pas été exécuté comme ça. Dans ce cas, nous aurions eu la bonne valeur ici,
mais ils l' ont lu en même temps ou
assez proche avant que cette opération d'incrément puisse se produire. cette aprèscetteopération d'incrément se produit sur les deux threads. Et dans cet exemple, nous ne restons toujours qu'avec x plus 1 car ils ont vu la même valeur initialement. C' est donc un peu le problème que nous voyons ici. Je suis évidemment qu'on voit ça se produire beaucoup plus d'une fois. Mais nous pouvons voir que ces opérations dans ces threads augmentent. Et dans ce cas, nous devons juste augmenter ce nombre pour nous
assurer que nous augmentons nos chances que quelque chose comme ça se produise. Nous entrons dans cette condition de concurrence où la valeur est accessible par plusieurs objets en même temps, chacun effectue l'opération, puis leur remplacement de la valeur. Mais parfois, les changements que nous obtenons ne sont pas ceux que nous attendons. Depuis deux threads incrémentent x par un. Et donc on n'aura pas de plus deux ici, on en aura un plus un. Évidemment, ce n'est pas toujours le cas parce que nous avons, vous savez, nous sommes, nous sommes presque à mi-chemin. Si je regarde ces chiffres, crie, donc on est à mi-chemin. Mais évidemment, cela se passe beaucoup. Alors, qu'est-ce qu'on peut faire à ce sujet ? Eh bien, il y a ce truc cool appelé un verrou, c'est aussi pour ça que nous avons appelé notre dossier verrouillé. Donc on va aller dans la classe de threading et on va initialiser un verrou. Maintenant, les deux méthodes qui sont disponibles dans cette classe de droit qui nous intéresse vraiment vont être verrouillées dot acquisition et Locke, Locke dot release, commenter ceux-ci. Ce sont donc ceux qui vont être des tests intéressants. Et ce que ceux-ci font, c'est mettre un, essentiellement initier une serrure. Donc, à ce stade, il s'agit d'une opération de blocage et rien d'autre ne peut se produire pendant que ce verrou est acquis. Donc, ce fil a fondamentalement revendiqué la serrure. Et il dit que je cours en ce moment jusqu'à ce qu'il le libère ou en fait jusqu'à ce qu'un autre thread libère ce verrou, alors rien que nous ne pouvons plus rencontrer ces, ces conditions de course. Donc, ce qui se passe dans ce cas, c'est la menace. La menace va commencer et il va lire la contre-variable. Mais le premier fil va commencer et il va dire, Oh, je suis la gorge est, le fil est verrouillé. Et puis il va lire la variable de compteur. Il va l'incrémenter d'un. Et puis c'est un peu dire relâcher le verrou. Et puis nous allons avoir un fil différent, qui va aussi se verrouiller. Et puis il va vous voir le résultat ici, qui est x plus 1. Et puis nous allons avoir x plus 1 plus 1, qui va être x plus 2. Et puis nous relâchons à nouveau le verrou. Maintenant, évidemment, dans ce cas, nous sommes en quelque sorte en train de rompre une partie du parallélisme qui nous était disponible et de forcer des opérations séquentielles. Évidemment, nous ne voulons pas tout verrouiller tout le temps parce que sinon nous ne gagnerons pas beaucoup d'avantages. Mais encore une fois, si vous y pensez jusqu'au tout début,
nous utilisons le threading, principalement lorsque nous bloquons les opérations d'E/S réseau. Donc, quand il y a beaucoup de temps passé entre les allers-retours réseau, et que nous ne voulons pas simplement rester inactif en attendant une réponse. C' est là que le filetage va vraiment s'épanouir pour nous. Donc, dans ce cas, lorsque nous effectuons des opérations localement, nous pouvons utiliser le verrouillage pour nous assurer que nos opérations seront cohérentes et que nous ne rencontrons aucune condition de course. Et encore une fois, le point de limitation va être plus vers les E/S réseau. Donc, évidemment, soyez juste conscient des effets de cela que vous aurez lorsque vous utilisez le verrouillage. Mais allons de l'avant et voyons cela en action. Donc ce qu'on va faire à chaque fois avant d'augmenter la valeur, parce qu'on va dire lock-down acquiert. Et après, nous allons relâcher cette serrure. Alors allons-y et continuons encore une fois. Et voilà, nous obtenons le résultat attendu. Maintenant. Donc, il y a une méthode que je, que je recommande d'utiliser ici cependant que je pense est un
peu plus propre puis verrouiller qui acquièrent, verrouillent et libèrent. Parce que lorsque vous appelez acquérir, vous avez juste à vous rappeler d'appeler aussi release. Sinon, vous allez commencer à rencontrer des problèmes. Voyons donc cela à petite échelle. Et lançons ça. D' accord. Donc je finis une fois parce qu'on ne relâche pas la serrure. Donc, nous avons essentiellement acquis un verrou et sur rien d'autre ne peut fonctionner jusqu'à ce que ce verrou soit libéré par quelque chose. Donc je vais interrompre ça. Donc, évidemment, on ne veut pas oublier ça. Donc, la façon la plus simple de le faire dans Python est d'utiliser le Gestionnaire de contexte. Donc ce qu'on peut dire, c'est avec Locke, on va incrémenter le compteur d'un. Donc, ce que cela fait est tout dans ce retrait ici. Alors, frapper. Et vous êtes en train de verrouiller. Tout ce qui
est dans ce retrait ici va être dans le bloc point acquiert puis verrouillé la libération. Donc, dès que nous sortons de ce retrait, où essentiellement appeler ici loc dot libération. Et au tout début de cette NND, nous allons appeler l'acquisition d'ordinateurs portables. Mais cette façon est évidemment un peu plus propre parce que nous n'avons pas à appeler la version réelle. Nous n'avons pas à nous assurer de ne pas les oublier parce que cela peut être problématique, surtout si vous avez des programmes qui vont fonctionner pendant un certain temps de toute façon. Et il vous faut du temps pour
comprendre que vous avez oublié de relâcher la serrure. Donc, au lieu de cela, nous pouvons simplement utiliser le gestionnaire de contexte et dire avec verrou. Et puis tout ici sera entre cette serrure qui a acquis au tout début et enfermé ou du moins à la fin. Et nous n'avons pas à nous soucier oublier que nous avons oublié de libérer la serrure. Et donc nous pouvons voir nous aussi revenir aux dix à six que nous étions à quatre ans. Ici, nous devrions aussi obtenir la formule à laquelle nous nous attendions. Donc, c'est juste une chose importante à garder à l'esprit car auparavant nous utilisions des files d'attente pour tout ce qui est thread-safe. Mais parfois, si vous faites d'autres choses, surtout si vous accédez à des variables partagées, il peut y avoir des problèmes là. Alors pensez simplement à la façon dont votre programme interagit. Et si vous avez besoin d'utiliser des verrous et si vous savez que vous êtes en eux. Si vous avez écrit un programme où potentiellement vous pourriez rencontrer une condition de course, gardez
simplement à l'esprit que le verrouillage va être un outil important à utiliser là pour vous assurer que vous obtenez réellement les bons résultats que vous Je m'attends.
16. Introduction multitraitement: Bon, maintenant que nous avons vu beaucoup de choses sur le threading,
allons de l'avant et jetons un coup d'oeil au multitraitement. Maintenant, d'abord, je veux juste écrire un script de thread simple à nouveau. Et puis j'ai déjà mon moniteur d'activité ouvert afin que nous puissions surveiller ou l'utilisation du processeur un peu. Et puis nous allons voir comment cela change quand nous allons au multitraitement. Donc, je vais dire à partir d'un thread, je vais importer le thread. Nous allons avoir une fonction ici qu'il va juste dire des valeurs de vérification dans la liste. Et il va prendre quelques listes, on appellera ça X. et ce qu'il va faire ici c'est qu'il va y avoir une boucle. On dira pour moi à portée. Et faisons dix à la puissance de huit, donc 100 millions. Et tout ce qu'on va faire, c'est qu'on va vérifier si j'ai un X ,
et ensuite on va créer des threads. Donc, nous allons dire que le nombre de threads va être quatre. Et nous aurons notre liste de threads ici. Nous allons garder une trace de ça. Et je dirai que pour moi dans la gamme nombre de threads, nous allons créer le thread. On va l'avoir. La fonction cible doit être cette valeur de vérification dans la liste. Et les arguments que nous allons
lui fournir seront la liste que nous voulons utiliser. Donc, nous allons dire liste de comparaison. Ça va être égal à 1, 2, 3. Fournissez cela en tant qu'entrée. Donc, ce que nous allons faire est que nous allons juste vérifier quatre threads différents en boucle sur plus 100 millions de valeurs pour voir si l'
une de ces valeurs est dans ce thread. Donc, fondamentalement, il suffit de faire quelques opérations CPU sans aucun composant réseau. Et bien sûr, nous voulons ajouter ces threads à notre liste où nous gardons une trace d'eux. Et je dirai pour les threads tn, nous allons commencer nos threads et nous dirons pour 10 threads, alors nous allons aussi rejoindre ou menaces. Et nous allons aussi juste importer le temps ici. Et juste avant de commencer, nous dirons que l'heure de début est chronométrée. Et puis nous dirons que tout a pris. Nous ferons le temps .Deltatime moins temps de début, secondes. Ok, donc ce que nous avons fait ici, c'est juste un programme de threading de base. Nous commençons et rejoignons nos discussions, bien sûr, comme nous en avons beaucoup parlé récemment. Et nous avons juste la liste simple qui contient trois valeurs et pour quatre threads différents, nous allons juste dans chaque boucle de thread sur. Donc, nous allons faire beaucoup d'opérations de répétition, de
répétition en fait, pour chacune d'entre elles, nous allons juste vérifier si la valeur est à l'intérieur. Et puis nous allons juste chronométrer toute cette opération pour voir combien de temps tout cela prend. Donc je vais juste commencer notre fonction principale ici. Et si nous allons voir notre moniteur d'activité, alors nous pouvons voir qu'il y aura, bien
sûr, un petit pic, ce que nous attendrions. Parce qu'il est évident que quelque chose va marcher. Nous pouvons réellement voir notre processus Python ici font maintenant juste du travail. Et ça va prendre un peu de temps pour finir tout ça. Mais j'espère que ça finira bientôt. Très bien, donc il a fallu environ 33 secondes et nous pouvons voir notre CPU est une acclamation, pas super significative, bien sûr, un peu plus clairement au-dessus des valeurs standard que nous avons,
mais nous pouvons voir en général combien de temps cela a pris. Donc, bien sûr, parce que nous n'avons pas vraiment de composants réseau, beaucoup de choses se passent l'un après l'autre, euh, parce que nous n'avons pas vraiment de composants réseau en attente. Alors maintenant, au lieu d'utiliser le threading, allons de l'avant et utilisons le multitraitement. Donc, nous allons dire à partir du multitraitement, nous allons importer la classe de processus. Maintenant, la bonne chose à propos du traitement et la bibliothèque de multitraitement est qu'il est en fait très, très similaire en termes de la façon dont il est écrit dans la bibliothèque de threads. Donc, bien que nous ayons à faire vraiment est juste changer ces noms vraiment pour la lisibilité. La seule chose que nous devions changer, c'est cette chose ici. Et maintenant, nous allons utiliser le multitraitement à la place. Donc, ce que nous allons faire, c'est que nous allons le faire, et mettons à jour ceci pour que ce n'est plus le nombre de threads, c'est le nombre de processus. Nous allons créer quatre processus distincts. Alors on va les commencer comme on l'a fait avant. On va attendre qu'ils finissent comme avant. Nous fournissons les arguments ici comme nous l'avons fait avant. Et la fonction que nous appelons n'a pas non plus changé. Donc, nous faisons exactement la même chose, mais maintenant nous utilisons le multitraitement. Alors allons de l'avant et lançons ça. Et je vais ouvrir notre moniteur d'activité. Et maintenant, tout d'un coup, vous pouvez le voir craquer. Et puis une seconde ici, nous allons avoir quatre processus. C' est donc le nombre de processus que nous avons réellement créés en cours d'exécution. Donc, ce qui se passe dans ce cas, c'est que nous utilisons en fait plus d'un noyau. J' ai donc plus d'un cœur disponible sur ma machine. Et donc, à cause de cela, nous pouvons en faire plus usage. Maintenant, évidemment, comme nous pouvons le voir ici, sont la vitesse n'est pas exactement proportionnelle. Il y a d'autres facteurs en cours. Donc, l'une des choses que vous auriez vu est que l'utilisation du CPU pour les quatre processus n'était pas la même que l'utilisation du CPU que l'un des processus avait. Donc, je pense, ainsi que la surveillance de cela, il a dit environ 80 pour cent pour chacun des processus, alors que la menace en fait presque 99. Quelque chose. Une utilisation beaucoup plus élevée dans ce sens. De toute évidence, nous devons laisser de la place pour d'autres choses qui se passent aussi, et notre système d'exploitation, nous nous occupons généralement de cela, mais nous pouvons voir que nous avons encore une amélioration de la vitesse. Et la quantité d'amélioration de la vitesse que nous pouvons obtenir d'ici dépend beaucoup du nombre de cœurs disponibles sur notre machine. Donc, plus nous avons de cœurs, plus nous pouvons créer beaucoup de processus, mais plus nous pouvons exécuter de processus simultanément, parce que nous pouvons exécuter chacun d'eux sur un noyau différent. Et c'est donc vraiment ce qui se passe dans ce cas, c'est à chaque fois que nous créons et démarrons ce processus, nous prenons cet interpréteur Python et nous commençons essentiellement une version semi fraîche sur un autre processus afin qu'ils ne soient pas conflictuelle et qu'il n'y a pas de verrou d'interpréteur global en cours. Donc, ceux-ci ne sont plus entravés entre ce verrou d'interpréteur global. Et donc l'avantage que nous en tirons est l'accélération. Maintenant, comme nous l'avons dit au tout début, threading est ce que nous allons l'utiliser pour fortement limité par les E/S réseau. Alors que le multitraitement est ce que nous voulons faire pour limité par l'utilisation
du processeur ou les processus intensifs du processeur, qui dans ce cas il n'y a pas de réseau ou d'attente ou quoi que ce soit. C' est juste l'utilisation du processeur, en vérifiant si une valeur est dans une liste. Et donc, nous pouvons voir, évidemment, nous allons engendrer un peu meilleurs résultats de notre multitraitement.
17. Quen en d'une file d'attentes multitraitement: Donc, évidemment, nous pouvons améliorer la façon dont nous faisons notre programme ici par plutôt que de refaire la même charge de travail, quelque chose qui serait généralement plus approprié à fonction de
multitraitement serait de diviser notre charge de travail sur différents segments. Donc, disons qu'au lieu de refaire la même chose pour des moments différents, nous voulons juste répartir notre charge de travail. Donc, nous allons avoir quelques paramètres supplémentaires ici. Ce sera notre, nous allons juste l'appeler IA maintenant
et, puis nous allons avoir un nombre total de processus. Donc ce que nous allons faire ici, c'est que nous allons essentiellement utiliser son œil et notre nombre total de processus pour diviser cela en seaux de taille égale. Donc, nous allons commencer par avoir fondamentalement une limite inférieure, qui va être I fois 10 à la 8. Et puis nous voulons aussi avoir une limite supérieure qui va être éteinte. Nous n'avons même pas besoin du nombre total de processus ici, qui va être I plus une fois 10 à la 8. Et nous pouvons même enlever cette valeur, extrait un abstract loin dans une autre variable. Donc on va dire que le nombre maximum pour vérifier 2 sera de dix à la huitième. Et alors nous allons commencer à partir de notre limite inférieure. On va aller à notre limite supérieure. Donc, nous allons dire de moi dans la gamme inférieure à supérieure. Et par exemple, si on a 0 ici, on va passer de 0 à fondamentalement, eh bien, une fois ça. Nous avons donc besoin d'un certain nombre de processus. C' est là qu'il est entré. Nombre de processus. Et nous allons juste diviser ceci ici par le nombre de processus et convertir tout cela en un entier. Depuis notre fonction de plage ici quires que nous utilisons un entier. Donc nous allons passer de, la première étape va être de 0 à une fois ce nombre divisé par le nombre de processus. Donc ça va être 1 sur 4 sur 10 millions sur 100 millions, ce qui va être 25 millions. Et quand j'en serai un, on passera de 25 millions à 50 millions. Donc ça va être 2 fois 25 millions. Et alors on va y aller et ces étapes. D' accord, donc l'œil que nous avons déjà ici, je suis de notre oeil ici, le nombre de processus que vous avez déjà, parce que c'est ce que nous définissons dans cette boucle de gamme ici. Donc, ce que nous faisons dans ce cas est, eh
bien, en ce moment, nous venons de le réécrire pour en faire
un programme au moins semi-réaliste pour comprendre ou voir comment nous pouvons simplement répartir la charge de travail. Et si nous le faisons à nouveau, alors évidemment dans notre surveillance de l'activité ou en second lieu, nous allons voir votre charge CPU, charger ici pic. Mais évidemment, ce sera beaucoup plus court parce que nous ne faisons pas la même chose quatre fois, mais au lieu de cela, si nous divisons cette opération en quatre processus distincts. Donc oui, donc généralement Bien que, nous ne voulons pas seulement avoir cette information, mais nous voulons aussi l'utiliser. Nous avons donc beaucoup vu auparavant que nous pouvons réellement utiliser la file d'attente pour transmettre des informations. Et nous pouvons faire une chose similaire ici. Nous pouvons toujours utiliser notre file d'attente et nous pouvons créer une instance de la classe à l'extérieur. Et nous pouvons également fournir cela en tant que contribution, comme nous l'avons fait ici. Et donc peut-être que l'information que nous voulons transmettre est un compartiment à chaque fois, combien de valeurs sont dans notre liste et combien de valeurs ne sont pas dans notre liste. Donc, nous aurons une variable qui a le nombre de hits, va juste être 0. Et puis nous allons juste dire si x, nous allons incrémenter ou nombre de hits par un. Et puis à la toute fin, nous allons mettre cette valeur dans la file d'attente avec inférieure, supérieure et un certain nombre de hits. De cette façon, nous pouvons faire un peu de traitement. Nous pouvons effectivement utiliser les informations des résultats que nous traitons. Donc, nous allons juste vérifier dans chaque
plage de compartiments combien de nos variables sont réellement dans cette liste. On va mettre ça dans une file d'attente. Et puis ici vers la fin, nous voulons aussi juste mettre fait dans la file d'attente. Et puis nous allons avoir juste une simple boucle while qui va dire tout. Et puis nous allons dire que v est égal à Q point obtient. Si v est égal à fait, nous allons éclater. Sinon, nous avons notre nombre inférieur ou supérieur de hits et Veeam. Et nous allons dire entre le bas et le haut, nous avons le nombre de valeurs de hits dans la liste. D' accord, alors allons courir ça une fois de plus. Et encore une fois dans notre graphique CPU, nous pouvons voir le petit pic ici. Donc nous pouvons voir maintenant que nous avons de bonnes informations. Donc entre, dans ce cas, 0 à 25 millions, nous avons trois valeurs dans la liste, évidemment, parce que nous avons 123 dans la liste. Et puis entre les autres, nous n'avons pas beaucoup d'informations. Donc, le but de cette leçon est que nous pouvons voir nous pouvons toujours continuer à utiliser Q de la même manière que vous l'avez utilisé auparavant, mais être capable de transmettre des informations sur les
processus entre et ou différents threads comme nous l'avons fait auparavant. Mais maintenant, il va être entre les différents processus et l'utiliser là-dedans. Et j'espère que vous pouvez voir que nous
pouvons utiliser des processus pour répartir la charge de travail. Évidemment, l'exemple que nous avons ici est un exemple très simplifié. Mais nous pouvons encore économiser un temps décent au lieu d' utiliser leur exécution en série en faisant tout en même temps. Ou même le filetage où cela va être fondamentalement la même chose parce que nous sommes tellement intensifs en CPU, avons
pu utiliser plus le nombre de cœurs que nous avons disponibles sur notre machine. Et en fait, utilisez davantage de notre processeur pour nous aider à terminer ces calculs plus rapidement. Maintenant, c'est important pour un, si vous exécutez des trucs sur votre propre machine, vouliez
juste finir plus vite et que vous avez beaucoup de ressources qui sont juste assis inactif. Cela peut évidemment vous aider à parler de programmes, mais aussi si vous déployez des applications et que vous avez des ressources CPU supplémentaires disponibles, si vous n'utilisez pas ces ressources, elles vont rester inactives et vous allez payer pour mais vous n'allez pas en faire usage. Donc, évidemment, cela dépend, vous savez, si vous avez un seul cœur sur tout ce que vous déployez, alors ce multitraitement n'aidera pas beaucoup parce que vous n'avez toujours qu'un seul cœur disponible. Mais si vous finissez par avoir une machine ou avoir un déploiement où vous avez plusieurs cœurs CPU disponibles. Vous voulez vous assurer que vous pouvez en faire le meilleur usage.
18. Pool multitraitement: Très bien, donc, jusqu'à présent, nous avons vu comment nous pouvons utiliser le multitraitement pour nous aider à distribuer une partie de notre travail sur différents processeurs. Et évidemment, le modèle que nous voyons ici est très similaire
au modèle de filetage avec lequel nous étions allés en détail précédemment. Et vous pouvez probablement déjà deviner. Mais la façon dont nous avons fait l'héritage de classe avec thread et tout ce que nous avons fait quand nous avons créé nos travailleurs de threads, nous pouvons faire la même chose avec la classe de processus. Ainsi, nous pouvons hériter de la classe de processus et nous pouvons avoir un début et des méthodes de jointure définies dans ainsi que leurs méthodes d'exécution. Et nous pouvons fondamentalement aborder la création d'un programme multi-traitement autour de classes multitraitement qui inhibent et héritent de cette classe de processus, tout comme nous l'avons fait quand nous avons traversé toutes les choses de thread. Et nous n'allons pas suivre cette voie parce que nous l'avons déjà fait pour le filetage. Et évidemment, il y aurait beaucoup de choses répétées que nous allons descendre. Donc sachez simplement que ce que nous avons fait pour le threading et les approches que nous utilisons dans la syntaxe va presque être identique au multitraitement, sauf que plutôt que d'utiliser la classe de thread, vous allez plutôt utiliser le processus ici. Donc, ce que je veux vous montrer maintenant, c'est parfois quand nous écrivons un programme de thread, auparavant il y avait beaucoup d'E/S réseau et il peut être logique de les avoir comme développer
des programmes complexes pour nous pouvons utiliser des indices pour passer tous les état sur interne. Et alors qu'un thread différent est responsable de différents services que tous les types de traiter avec la charge du réseau là-bas. Mais parfois, quand nous faisons du multitraitement, nous avons un peu coupé notre flux de travail et plutôt que de tout réécrire, nous savons juste, oh, voici quelque chose que je veux optimiser. Et évidemment, nous pouvons faire la même chose avec thread si nous avons comme un petit composant où nous sommes comme, oh, voici beaucoup de choses de réseau que je peux essentiellement optimiser et savez-vous, plutôt que d'attendre et de sérialiser, Je peux juste faire toutes ces choses et essentiellement la moitié de tous les threads afin que l'attente se passe presque simultanément. Mais pour le traitement maintenant, je veux juste me concentrer sur ce composant. Et plutôt que de générer des processus individuels comme celui-ci, en utilisant des files d'attente pour transmettre des informations, je veux juste simplifier beaucoup cette chose. Et ce que je veux faire à la place, c'est que je veux finalement arriver
au point où je peux juste passer nos limites inférieure et supérieure. Et fondamentalement genre de juste distribué ce travail pour nous et ensuite juste obtenir comme un centre de valeur de retour. Prenez le q ici pour sortir ce Q. Donc je ne veux pas utiliser de repères ou quoi que ce soit. Fondamentalement, je veux juste avoir une variable que je peux avoir comme une variable de résultat qui va dire quelque chose comme 30, 0, 0, et pour que je puisse continuer à utiliser cela. Maintenant, avant de le faire, commençons par quelque chose de plus simple. Nous allons juste commencer avec le pool de traitement de base et nous allons avoir une fonction beaucoup plus simple où nous allons juste tout caler. Donc nous allons revenir beaucoup aux bases, revenir à des exemples beaucoup plus simples. Et nous allons juste avoir une fonction simple d'abord qui nous permet de tout caler. Parce qu'en fin de compte, une fois que nous pouvons faire cela, nous pouvons alors faire des choses plus compliquées dans la syntaxe, point diffère un peu de la façon
dont nous utilisons le pool, c'est pourquoi je veux commencer par cet exemple
très simple afin que nous pouvons simplement voir comment cela fonctionne et comment nous pouvons obtenir ce résultat. Ensuite, nous pouvons procéder à la mise à jour ou à la syntaxe afin que nous puissions faire le toujours pas super compliqué, mais évidemment passer plus de variables et choses que nous avions avant. Donc, au lieu d'utiliser le processus, nous allons maintenant utiliser la classe pool. Maintenant, avec la classe pool, nous pouvons l'initialiser en utilisant le contexte. Donc, avec piscine comme piscine ou comme P ou tout ce que vous voulez tire assez bien parce que, vous savez, est évidemment assez spécifique. Nous pouvons être plus précis et dire comme le multitraitement. Je suis sûr qu'il y a une faute de frappe ici quelque part. Pool de traitement. Ou si nous ne voulons pas tout écrire comme ça, nous pouvons juste écrire comme et les gens pour être un peu plus précis. Mais fondamentalement, nous allons juste initialiser cette classe de pool, puis l'utiliser dans le contexte. Donc maintenant, nous avons à notre disposition un pool de processus que nous pouvons utiliser. Donc, fondamentalement, et nous allons entrer dans ça dans une seconde. Mais nous pouvons définir ici le nombre de processus que nous voulons avoir disponibles dans notre pool. Par exemple, qui a mis le numéro deux ? Et ici, cela signifie que nous avons le potentiel, mais nous n'avons pas nécessairement besoin de l'utiliser de deux processus qui sont à notre disposition
et nous pouvons continuer à effectuer des opérations et, fondamentalement, à prendre ces processus. Mais une fois que tous ces processus sont supprimés du pool, ils ne sont plus disponibles pour nous et nous devons essentiellement attendre que le processus renvoyé au pool afin que l'opération suivante puisse ensuite l'utiliser. Donc encore une fois avec nous, nous sommes fondamentalement, ils vont juste créer comme un petit, vous pouvez l'imaginer comme un petit seau. Et dans ce seau, nous avons un certain nombre d'articles disponibles. Et on peut sortir de ce seau. Et une fois que ce seau est vide, nous devons attendre que, vous savez, quelque chose, quelqu'un remette l'objet qu'il a retiré. Et une fois que quelque chose est encore dans le seau, on peut le retirer. Donc, en ce moment, nous avons un pool de taille 2, ce qui signifie que nous avons deux processus à notre disposition que nous pouvons utiliser, ce qui signifie essentiellement que nous pouvons utiliser pour suivre, puisque chaque processus va engendrer un nouveau noyau. Donc ce que nous allons faire ici, c'est que nous allons utiliser une nouvelle méthode. Nous allons utiliser notre multitraitement cool. Et nous allons utiliser cette méthode de carte. Et ici, nous allons mettre la fonction que nous voulons utiliser. Donc ça va être la place. Et puis nous allons également fournir nos variables d'entrée ici. Et nous allons enregistrer tout cela dans une variable de résultat. Et nous pouvons retirer le composant temps ici, puisque nous ne l'utilisons plus. Et allons-y et imprimons notre résultat. Cela ne peut pas simplement exécuter notre fonction principale. D' accord ? Donc, fondamentalement, nous avons exactement ce que nous attendions, c'
est-à-dire que nous avons pris notre liste d'entrées ici et nous avons obtenu le carré de chaque valeur. Mais maintenant, la chose intéressante que nous avons avec nous est que nous sommes capables d'utiliser ce pool et que nous sommes en mesure d'appliquer cette méthode de carte là-bas. Et nous allons juste le faire, il va essentiellement appliquer ceci à chaque composant. Donc, il va être itérer à travers ces un par un. Mais nous allons récupérer la même structure, mais avec nos valeurs mises à jour en interne, même si nous opérons simplement sur une variable, nous pouvons retourner ceci et obtenir fondamentalement notre nouveau résultat, qui va être notre liste originale ici sur nos listes de comparaison pour le moment. Mais ça va être carré. Donc, chaque valeur ici va être quadrillée. Maintenant, cette valeur, évidemment, cela peut dépendre de la machine que vous êtes à court. Parfois, vous ne pouvez utiliser qu'un seul CPU car vous n'en avez qu'un seul disponible. Parfois, vous pouvez quatre, six, huit ou
16 ou peu importe le nombre que vous avez disponible sur votre machine. Alors, comment pouvons-nous améliorer ce petit peu pour qu' il puisse réellement s'adapter à la machine sur laquelle il fonctionne. Eh bien, il y a cette fonction cool que nous pouvons importer appelée un nombre de CPU. Et le nombre de CPU, comme vous l'avez peut-être deviné,
il va juste nous donner le nombre de CPU que nous avons disponibles. Donc, ce que vous pouvez faire est que vous pouvez dire le nombre de CPU disponibles. Ça va l'être, et nous allons juste invoquer notre nombre de CPU. Donc, pour juste imprimer ça. Et vous pouvez voir ma machine pour laquelle il va tourner puisque j'ai quatre carbones disponibles. Mais cela peut différer en fonction de la machine sur laquelle vous exécutez. Mais peut-être que le nombre de CPU que vous voulez utiliser sera de 1 de moins que le nombre de CPU disponibles. Parce que si vous utilisez tous vos cœurs, alors il y a, vous savez, tout va être utilisé. Et donc il se peut qu'il n'y ait pas assez de CPU pour que d'autres choses continuent. D' autres processus du système d'exploitation, par exemple. Donc, en général, ce que vous voulez faire est que vous pouvez dire que le nombre de CPU à utiliser sera notre nombre de CPU moins un. Mais dans le cas où nous n'avons qu'un seul noyau, nous voulons dire, d'accord,
eh bien, ce sera le minimum. Donc, je vais juste être pensé le maximum entre un et le nombre de CPU disponibles minus1. Et puis on peut utiliser ça ici. Donc, dans ce cas, par exemple, je peux imprimer le nombre de CPU utilisés. Et maintenant, nous allons montrer trois, puisque ce sera la valeur maximale entre 14 moins un, ce qui est trois. Donc, la valeur maximale entre ces deux va être trois. Mais dans le cas où nous n'avons qu'un seul CPU, donc nous l'sommes, cette valeur est une. Nous allons plutôt utiliser la valeur par défaut. Puisque évidemment nous voulions encore faire quelque chose. Donc, de cette façon, nous pouvons dire, d'accord, donc en fonction de la machine sur laquelle nous
fonctionnons, nous pouvons voir le nombre de CPU disponibles. Et puis nous pouvons faire en sorte que notre regroupement soit de cette taille, que beaucoup de processus sont disponibles pour nous de tirer. Et puis nous pouvons mapper sur ces objets d'entrée dans la fonction que nous voulons utiliser pour cela et ensuite obtenir ces juste valeur de retour vraiment agréable que nous pouvons simplement continuer à utiliser. Alors plutôt que d'avoir à faire cette céréale. Donc, nous itérons et nous disons k pour I dans la gamme de si longue ou liste est. Et puis on va au carré et on va mettre ça dans une nouvelle liste. Nous allons, nous allons mettre à jour notre valeur, quelle que soit la valeur, puis continuer à utiliser comme ça. Nous pouvons simplement utiliser ce pool de multitraitement et mapper fondamentalement ces valeurs dans notre fonction et juste obtenir les valeurs de retour mises à jour afin que nous puissions continuer à utiliser cela. Parce que ceux-ci, ces dysfonctionnements peuvent se produire en parallèle parce que évidemment cela ne dépend pas de quoi que ce soit d'autre autour d'elle. Et donc avec cela, nous sommes capables d'évoluer, utiliser ceci pour accélérer très rapidement certaines parties de notre code qui n'ont pas nécessairement besoin d'un refactoring complet, comme la façon dont nous avons vu avec le thread. Mais vous savez, juste une petite ligne ici pourrait vraiment nous aider à distribuer beaucoup de travail. Et puis nous pouvons continuer de façon régulière.
19. Arguments multiples: Bon, donc maintenant, vous allez probablement vous demander, ok, eh bien, comment puis-je passer plusieurs arguments ? Comment puis-je faire quelque chose comme ça ? Et je veux faire x, mais je veux faire x au pouvoir de y comme ça. Et je veux dire, vous savez, notre nouvelle valeur de puissance sera trois. Vous avez peut-être pensé ça. Je vais juste mettre cet argument supplémentaire ici et ça va s'en occuper. Malheureusement non. Et je vais te montrer ce qui va se passer, mais je dois annuler ça. Sinon, nous allons rencontrer un autre problème ici. Mais si nous exécutons ceci et nous regardons la sortie, nous ne transmettons plus les valeurs individuelles dans la liste ici, mais nous passons la liste elle-même. Donc, nous allons itérer sur chaque élément ici et passer cela en entrée. Donc, si nous mettons y ici, nous n'obtiendrons pas les résultats que nous voulons, peu importe si nous l'avons. Et voir ici, est-ce que nous appelons toujours, nous ne l'imprimons pas parce que notre fonction échoue
déjà parce que nous manquons un argument supplémentaire pour pourquoi. Et même si nous faisons quelque chose comme ça, aucun de ces deux ne fonctionnera pour nous. Alors, comment pouvons-nous fournir ce paramètre supplémentaire ici ? Eh bien, nous allons utiliser un paquet Python appelé func tools, qui vient déjà pré-installé avec Python. Et à partir de là, nous allons importer une méthode appelée partielle. Maintenant partielle va nous permettre de créer des fonctions partiellement définies. Donc on peut les appeler partiellement, mais ils ne seront pas complètement appelés. Mais nous pouvons déjà nous fournir certains des paramètres avance et ensuite nous pouvons le perdre plus tard. Maintenant, pour le faire, parce que la façon dont nous allons
fournir des paramètres va être dans un ordre spécifique. Et donc nous voulons nous assurer de laisser le paramètre qui va
être fondamentalement la variable qui va changer jusqu'à la toute fin. Donc, je vais créer une fonction partielle en utilisant la méthode partielle. Je vais avoir cette place ici. Et la valeur que je veux pour y sera notre pouvoir ici. Maintenant, je peux utiliser cette fonction partielle dans la méthode map et je peux enlever tout cela. Maintenant, notre carte va juste itérer sur cette fonction un par un, et elle va appeler cette fonction ici. Cette fonction est déjà partiellement définie en appelant la méthode racine carrée et en fournissant ce premier paramètre, puissance comme celle-ci. Donc si on fait ça maintenant, on va tout découper,
puisque c'est ce qu'on a ici. Évidemment, nous pouvons tout changer en puissance de quatre, comme nous l'avons fait ici. Et nous pouvons également étendre cela pour des paramètres supplémentaires comme l'addition, le composant. Et disons que nous voulons tout avoir au pouvoir de trois. Et puis nous voulons avoir un composant supplémentaire, et ce sera 2. Nous allons le fournir ici. Donc, nous allons juste ajouter cela au résultat à la fin. Donc si je fais ça, alors on va tout découper et ensuite on aura un plus deux qui vient de cette faute de frappe ici. Donc, nous pouvons voir si nous voulons utiliser la méthode de la carte et nous voulons avoir des variables supplémentaires ici. On ne peut pas simplement transformer ça en un tuple ou une liste et ensuite penser que, oh ouais, tout va boucler dessus. Malheureusement, ce n'est pas ainsi que la méthode de carte fonctionne avec le pool de multitraitement. Mais si nous avons des variables fixes que nous avons déjà définies à l'avance que nous voulons juste fournir ici. Et notre dernière composante ici va être la chose qui va changer. Ensuite, nous pouvons réellement utiliser cette méthode partielle à partir des outils funk. Et ici, nous pouvons définir partiellement notre fonction. Et puis nous pouvons le remplir avec les différents composants que nous avons ici pour
appeler la fonction et c'est de façon complète et vraiment obtenir les résultats que nous voulons tout en ayant déjà certains des arguments passés.
20. Multitraitement d'arguments: Très bien, donc auparavant, nous avons vu que nous pourrions fournir des arguments
supplémentaires en utilisant cette méthode partielle dans nos outils func, une bibliothèque ici que nous avons importée. Et nous avons été en mesure de définir partiellement les fonctions ou de fournir partiellement les composantes des fonctions. Ensuite, nous pouvons utiliser notre méthode de carte ici pour fournir ce composant restant. Mais que faire si nous ne voulons pas ou n'avons pas de composants fixes, mais au lieu de cela nous voulons avoir une entité différente, par
exemple, certains impuissants. Et ici, ce que nous voulons faire, c'est que nous voulons avoir le premier élément ici, par
exemple, le pouvoir du second au pouvoir 5 et le troisième au pouvoir de six. Nous savons donc déjà ce que nous voulons fournir. Comment pouvons-nous faire cela d'une manière qui n'est pas comme ça, mais idéalement être en mesure de fournir cela directement et d'effectuer ces calculs. Donc, je vais faire un nettoyage rapide ici, supprimer ce truc, et aussi faire juste une réorganisation de nos paramètres de fonction. Juste pour l'avoir un peu plus devrait être de mentir. Un peu plus facile à voir. Et nous n'avons pas besoin de cette définition de fonction partielle ici. Donc ce qu'on veut faire, ou ce qu'on peut faire, c'est utiliser une méthode appelée « carte des étoiles ». Maintenant, dans notre carte des étoiles, nous pouvons fournir une entrée ici qui a ce qui suit, qui ressemble à ceci. Et puis à l'intérieur, nous pouvons fournir des éléments
supplémentaires que nous pouvons parcourir si nous le voulons. Et tous ces éléments, nous pouvons ensuite passer en tant que paramètres individuels à notre fonction. Donc, par exemple, dans notre cas, ce que nous voulions faire est alors qu'un premier élément que nous voulons passer serait 1 et 4, puisque ce sera nos x et y. le second sera 25, puis le troisième ici est sera 36, puisque nous voulons fournir ces deux éléments ensemble et ensuite les fournir comme nos paramètres x et y. Et donc si nous fournissons ceci comme entrée, alors fondamentalement ce que nous allons obtenir est l'exécution comme celle-ci. Et évidemment, nous utilisons qui le pool de multitraitement encore. Nous allons donc être en mesure d'utiliser différentes couleurs pour nous aider à le faire. Donc, ce que nous devons faire maintenant, c'est que nous devons regrouper ces deux listes afin que nous puissions obtenir ce format ici. Et puis nous pouvons fournir cela comme une entrée. Donc nous allons avoir notre liste préparée, qui va juste être vide liste avec laquelle nous allons commencer. Donc, nous allons juste itérer sur la longueur de cette liste. Et donc nos éléments que nous voulons ajouter ici vont juste être, nous voulons avoir ici, notre premier élément va toujours venir de notre liste de comparaison. Ce sera le premier élément ici. Et le deuxième élément que nous voulons, il va provenir de notre liste de puissance, que nous pouvons mettre 0. Nous voulons le ème composant. Et donc nous pouvons imprimer la dernière fois que nous allons insérer des listes à utiliser comme entrée. Ça va être ça. Et ensuite, on pourra faire ça. Et puis nous serons en mesure de fournir chacun des éléments à l'intérieur comme l'un des paramètres ici. Alors allons de l'avant et lançons cette boucle. J' ai une faute de frappe ici. Et j'ai aussi oublié de mettre à jour. Ça monte ici. Essayons encore une fois. On y va. C' est donc la liste que nous utilisons comme entrée. Et nous pouvons voir que notre x et notre y. donc ce sont nos paramètres de fonction que nous passons. Donc ça va être votre x et notre y, notre X et notre Y, ou X et notre Y. Donc nous faisons un à la puissance quatre, qui est 12 à la puissance de cinq, qui devrait être 32, et 3 à la puissance de six, qui devrait être 729. Donc, nous pouvons voir qu'en utilisant une carte en étoiles, nous sommes en mesure de fournir plusieurs paramètres d'entrée, surtout si, vous savez que ceux-ci vont changer. Il est juste important de s'assurer que nous avons ce genre de structure pour que nous puissions les transmettre. Et puis les éléments ou les valeurs que nous transmettons dans notre fonction vont être dans l'ordre où nous avons les paramètres dans notre fonction ici. Et donc de cette façon, nous sommes en mesure de passer plusieurs paramètres. Donc, la chauve-souris, nous n'avons pas besoin d'utiliser ces définitions
fonctionnelles partielles, de fonctions si plus d'une de nos variables varie.
21. Éléments de contrôle multitraitement dans la liste dans certaines fourches: Bon, Revenons enfin à notre fonction initiale légèrement plus intensive de CPU que nous utilisions, qui va juste vérifier si une valeur ou combien de valeurs dans notre liste de comparaison sont réellement dans une plage spécifique. Donc, peut dire, appelez ceci par exemple, vérifier le nombre de valeurs dans la plage. Et puis nous allons avoir ici va être notre liste de comparaison. Et là, nous allons avoir nos limites inférieures et supérieures. Et puis nous voulons suivre les chiffres. Et puis nous voulons dire pour moi dans la gamme de la limite inférieure à notre limite supérieure. Si les yeux et notre liste ici. On veut juste incrémenter ça d'un. Donc oui, il nous manque un I ici et à la fin on veut juste retourner le nombre de hits. Donc encore une fois, le but de cette fonction n'est pas vraiment de faire quelque chose de plus sauf d'être quelque chose d'une façon quelconque, pour nous de simuler juste
un peu plus d'une tâche de calcul intensive parce qu'elle va prenez un peu de temps pour calculer cela. Donc les différentes gammes inférieures et supérieures que nous allons avoir. Et si nous le voulons, nous pouvons simplement spécifier ces règles de plage. Appelons ces limites inférieures et supérieures. Et bien sûr, nous pouvons générer ces deux-là avec un peu de boucle. Mais en fait, si on se divise en quatre, on peut voir ce qu'on fait c'est qu'on va passer de 0 à 25 millions. Donc ça va être dix pour la puissance de six. Et puis on va passer de 25 millions à 50 millions de fois dix à la puissance de six. Et puis je vais juste copier ça. Et on va passer de 50 à 75 millions. Et enfin, on veut passer de 75 millions à 100 millions. Ce seront donc nos limites inférieures et supérieures. Maintenant, bien sûr, nous devons le mettre dans ce genre de format. Mais au lieu de cela, ce que nous voulons dans ce cas, c'est que nous
voulons essentiellement nos listes de comparaison pour la première valeur d'entrée. Et puis nous voulons notre bas et notre haut ici. Et puis nous voulions faire ça ou les autres aussi. Donc nous avons encore besoin de faire comme un peu de rejoindre comme nous l'avons fait ici. Mais comme nous n'avons pas beaucoup de valeurs ici, je suis juste plus facile de mettre ces quatre valeurs et à la main. Mais évidemment, nous pouvons écrire un peu pour boucle pour remplir cette liste pour nous aussi, surtout si vous vouliez aimer 50 ou 100 ou même comme 10 ou 20 équilibre différent. Ouais, de toute façon, donc encore une fois nous avons juste besoin de préparer notre liste. Nous allons donc utiliser notre liste de comparaison ici. Mais au lieu d'itérer sur cette longueur, nous allons fondamentalement ajouter ceci comme l'un des éléments ici. Et donc le nombre de valeurs d'entrée
différentes que nous allons avoir sera en fait les listes, la longueur de cette liste. Donc, nous voulons itérer sur la longueur de cette liste. Ici, nous voulons ajouter la liste de comparaison complète. Et nous voulons également ajouter les composants individuels. Donc ça va être notre première et notre deuxième valeur ici. Et puis nous allons fournir ceci comme intrant pour faire nos calculs. Donc encore une fois, ce que nous faisons c'est que nous prenons cette liste et nous avons essentiellement notre nouvelle liste préparée, qui va ressembler à ceci et comme ça. Donc c'est juste ce qu'on fait ici. Et puis ce composant ici va être notre première entrée ici, qui va être une liste. Et puis les autres seront nos limites inférieures et supérieures. Donc, je vais annuler cela évidemment parce que c'est ce que cette petite boucle ici comme quatre. Et puis allons de l'avant et lançons ça. Et donc nous pouvons voir que ces paramètres seront nos paramètres d'entrée ici. Chacun d'entre eux, comme nous l'avons dans les arguments de fonction, ce sera notre liste de comparaison, nos limites inférieure et supérieure. Et donc nous pouvons voir évidemment dans la première gamme, nous avons trois éléments qui sont contenus côté parce que leurs nombres sont 123. Et puis sur les autres, ils allaient tous avoir 0. Donc, c'est une sorte de revenir à ce que nous avons commencé avec quatre, désolé, exemple pour le multitraitement pour sorte de nous aider à faire cela. Et maintenant, nous pouvons utiliser notre méthode de démarrage dans ce cas pour fournir ces arguments d'entrée multiples comme nous avons ici. Maintenant, une chose que nous pouvons faire en fait pour simplifier un peu la syntaxe, est plutôt que de lister les listes comme celle-ci. Au lieu de cela, ce que nous pouvons faire est juste d'utiliser ce petit astérix. Et ce que ça va faire, c'est qu'il va décompresser toutes les valeurs ici. Donc vous pouvez voir si je réexécute ça, nous allons obtenir exactement les mêmes résultats. La seule différence est plutôt que moi d'avoir à référencer chacun de ces composants individuels comme nous l'avons fait ici. Cette étoile va essentiellement le déballer et il va prendre tous ces éléments et les fournir en tant que valeurs d'entrée supplémentaires une à la fois, suivant exactement dans l'ordre dans lequel nous les avons ici. Donc, c'est juste un petit raccourci que je peux utiliser plutôt que d'utiliser ceci parce que je veux obtenir tous les éléments. Mais si j'en ai
10, 20 ou 15, comme si ça allait s'allonger et ça va être fastidieux. Et donc vraiment ce que je veux faire, c'est que je veux juste avoir toutes ces valeurs ici, mais je ne veux pas qu'elles soient dans un format tuple comme celui-ci. Je veux juste tous les éléments individuels l'un après l'autre. Et la façon dont je peux le faire est d'utiliser l'étoile, qui va fournir chacun de ces éléments à l'intérieur comme valeurs individuelles ici. Donc, c'est juste un raccourci pour garder ça plus propre et aussi le rendre un peu plus rapide à écrire.
22. Introduction à l'écriture de programmes asynchrones: Bon, alors commençons à jeter un oeil programmes
asynchrones ou comment nous pouvons écrire un programme asynchrone. Et ce sera notre troisième option que nous avons pour la concurrence. Et vous remarquerez un point. Cela va probablement ressembler au threading,
bien qu'il soit à nouveau différent parce qu'avec les programmes asynchrones, nous n'avons qu'un seul thread qui est en cours d'exécution, et nous n'avons aussi qu'un seul processus. Alors, allons de l'avant et voyons ce qui se passe. Donc la première chose que nous allons faire est d'importer des E/S asynchrones, qui va juste nous aider avec tout ça. Maintenant, je suis sur Python version 3.7 et je recommande que vous travailliez également sur au moins la version 3.7 de Python. Mais aussi évidemment, bien sûr, si vous êtes sur une version ultérieure de Python, ce sera mieux juste parce que jusqu'à présent, la bibliothèque asynchrone a été un peu pas expérimentale, mais elle a beaucoup changé. Et à ce stade, il semble y avoir un état fixe avec la façon dont cela fonctionne. Donc, je recommande simplement généralement, assurez-vous que vous utilisez une version ultérieure de Python si vous le souhaitez. Ou au moins Python 3.7, qui est à nouveau ce que je suis en ce moment. Nous pouvons donc importer des E/S asynchrones et qui devrait être un paquet Python par défaut. Et puis nous pouvons commencer à définir notre première fonction asynchrone. Donc, nous pouvons le faire en ayant juste une fonction régulière. Par exemple, si nous voulons avoir une sorte de fonction de sommeil où tout ce que nous faisons ici est de dormir pendant, disons cinq secondes. Si au lieu de cela nous voulons le faire de manière asynchrone, alors nous mettrons en face d'ici le mot-clé asynchrone. Et puis ici, au lieu d'utiliser le sommeil chronométré, nous utiliserions effectivement une méthode de sommeil iOS de synchronisation. Et on parlera un peu plus du raisonnement dans une seconde. Mais fondamentalement ce que nous obtenons de
cela, c'est ainsi que nous allons définir une fonction asynchrone. Maintenant, nous devons faire une chose de plus ici, est-à-dire que nous devons réellement attendre cette fonction ou cette co-routine est en fait ce qu'elle s'appelle. Et vraiment ce qui se passe ici. Et tout le processus d'utilisation de l'exécution asynchrone et Python est, et nous verrons comment le faire en une seconde. Mais nous commençons quelque chose appelé une boucle d'événement. Et puis nous pouvons ajouter, commencer à ajouter des tâches ou des tâches de planification avec cette boucle d'événement. Et puis à l'intérieur de cette boucle d'événement aura des objets appelés ou auront des choses appelées futures. Et ces futurs représentent essentiellement quelque chose qui n'est pas encore revenu, mais quelque chose va en venir. Donc, cela peut sembler un peu déroutant, mais généralement que se passe-t-il si nous programmons plusieurs fonctions asynchrones ? Chacun d'eux fournira un avenir qui à un moment donné et ils finiront ou ils atteindront une sorte de point de contrôle. Et à partir de ce moment, nous pouvons faire la prochaine chose avec cette co-routine. Tout ce que nous avons défini ici, c'est généralement appelé une co-routine. Et ce sont les choses que nous ajouterons et planifierons dans nos boucles d'événements. Maintenant, au fur et à mesure que nous continuons à coder, j'espère que cela deviendra un peu plus intuitif et nous ne serons pas si perdus dans toute la syntaxe de tout. Mais évidemment, parce que nous ne traversons pas des choses asynchrones, il est important de mentionner et de parler à travers certains de ces mots clés et le début, mais aussi pendant que nous continuons à travers. Donc, si nous voulions lancer ceci, si nous appelons et renommons cela en sommeil asynchrone. Si on appelle un sommeil d'évier. Dormez comme ça. Malheureusement, il ne va pas vraiment courir. Nous allons avoir une erreur ici, qui est essentiellement liée à cela. Eh bien, pour commencer, il est dit que le Coubertin n'a jamais été attendu, c'est
ce que nous avons ici. Mais même si nous ajoutons ce mot-clé wait, il ne fonctionnera toujours pas parce que nous n'avons pas une boucle d'événement en cours d'exécution en ce moment qui consomme tout cela. Et à part cela, nous ne pouvons en fait pas utiliser le mot-clé wait en dehors d'une fonction qui n'est pas async def. Alors, comment pouvons-nous faire fonctionner ce truc ? Comment pouvons-nous faire fonctionner ces os nus ? Donc, nous allons créer une nouvelle fonction, qui va être notre fonction principale, que nous allons également définir avec async def. Et ce que nous allons faire ici, c'est que nous allons attendre la réponse de notre sommeil asynchrone. Maintenant, les mots-clés d'attente ici parce que nous avons cette boucle d'événement et nous pouvons avoir plusieurs co-routine différentes programmées là pour s'exécuter. Fondamentalement, ce que cela attend mot clé fait est qu'il donne contrôle à notre boucle d'événement pour continuer avec d'autres choses. Donc, fondamentalement, il dit au programme qu'à ce stade nous sommes, nous attendons une réponse et jusqu'à ce
que nous ayons cette réponse ou que nous ayons quelque chose sur lequel nous devons continuer. y a pas de raison de
me donner toutes les ressources parce que je ne peux rien faire tant que je n'aurai pas ça. Donc, c'est généralement le point d'un poids. Mais même si on a ça, on ne peut toujours pas appeler le principal Hulk. Alors, comment pouvez-vous faire courir le principal ? Donc, ce que nous pouvons faire est que nous pouvons utiliser cette méthode d'exécution de point d'E/S asynchrone. Et ici, nous allons mettre la co-routine principale que nous voulons exécuter. Et cela va essentiellement démarrer la boucle d'événement pour nous. Et il va commencer la consommation de la boucle d'événement et essentiellement prendre soin de l'ensemble du processus pour nous. Il existe d'autres méthodes. Par exemple, vous pouvez obtenir une boucle d'événement en cours d'exécution et vous pouvez exécuter jusqu'à fin ou ces autres choses qui sont plus spécifiques à la boucle d'événement. Mais vraiment en utilisant le point d'E/S asynchrone prendra soin de toute cette gestion pour vous et vous n'avez pas vraiment besoin de vous soucier de l'une des choses de niveau inférieur. Donc ça va être notre point d'entrée. Maintenant, une chose importante à noter est que nous ne pouvons avoir qu'
une seule boucle d'événement en cours d'exécution par thread. Et par défaut, nous ne l'exécuterons que sur un noyau et un seul thread. Donc, fondamentalement, ce que cela signifie, c'est que nous allons seulement avoir un appel de point d'IO asynchrone, qui va être le point d'entrée de notre programme. Et bien sûr, nous pouvons envelopper cela dans le si nom est égal principal. Um, donc pour exécuter le fichier principal ici, alors nous allons commencer avec peut aller dans cette boucle d'événement. Bon, alors allons-y et essayons ça maintenant. Donc nous exécutons le programme et tout ce que nous faisons est dormir
asynchrone pendant cinq secondes. Mais évidemment, il n'y a pas grand-chose d'autre à ce stade parce que nous ne faisons qu'une chose. Et même si nous redonnons le contrôle de la boucle d'événements, c'est
ce que nous faisons ici. n'y a rien d'autre en cours d'exécution, il n'y a rien d'autre qui se passe, donc il n'y a rien d'autre à continuer à travailler pendant ce temps. Alors ajoutons une deuxième fonction maintenant, qui va être une fonction asynchrone pour imprimer bonjour. Et tout ce que ça va faire, c'est qu'il va imprimer comme son nom l'indique. Bonjour. Bon, alors que se passe-t-il maintenant ? Si on planifiait comme ici ? Et puis nous allons mettre quelques impressions supplémentaires ici juste pour voir où nous en sommes dans notre programme. Donc tu vas le dire avant de dormir. Et puis on peut mettre une autre empreinte après. Ici. On va juste être après le sommeil. Bon, alors que se passe-t-il ? Nous avons, eh bien, nous survolons le point d'entrée. Donc, nous commençons essentiellement la boucle d'événement et nous commençons le x ou la planification de sa co-routine principale. Ensuite, nous allons dans cette routine principale de route ici. Et maintenant, nous allons à notre première ligne qui va attendre la réponse de cette co-routine de sommeil asynchrone que nous avons ici. Une fois que nous sommes entrés ici, nous imprimons avant de dormir, et puis nous avons cet appel d'attente. Donc, ce qui se passe avec l'appel d'attente est la façon dont l'appel ne bloque pas. Il permet l'exécution d'autres routines co. Cependant, il arrête l'exécution d'aller plus loin dans cette fonction. Donc, et si nous faisons ça, vous remarquerez que nous allons entrer dans cette fonction et ensuite nous appelons avant de dormir. Et puis on dort cinq secondes. Et puis nous allons dans l'après-sommeil. Et c'est seulement alors que nous passons à la deuxième déclaration ici. Malheureusement avec ça, nous ne pouvons pas passer à la prochaine chose. Cette attente est fondamentalement un point d'arrêt dans notre co-routine, dans notre exécution de programme comme spécifiquement dans cette fonction sont dans cette co-routine. Et c'est un peu là que nous nous arrêtons momentanément pour l'exécution. Et ça dit essentiellement, ou la fonction ou la co-routine à ce stade dit, je n'ai pas besoin de contrôle en ce moment. J' attends une réponse. N' hésitez pas à continuer à faire d'autres choses. Et puis notre boucle d'événements peut continuer et faire d'autres choses. Et chaque fois que cette fonction est prête, elle peut donner un signal disant, Hey, je suis prêt à continuer. Et puis le contrôle peut être rendu à lui. Mais parce que nous n'avons qu'une seule co-routine principale en cours d'exécution, et à l'intérieur de ceux-ci, nous appelons des routines tumorales Cole. Ceux-ci sont toujours exécutés séquentiellement et il
n'y a pas de routines co multiples programmées en même temps. Pour que lorsque nous atteignons cet appel d'attente ici, nous puissions continuer avec l'exécution d'une autre co-routine. Et nous allons voir comment faire cela dans la section suivante. Il y a une autre chose que je voulais vous montrer à l'avance cependant, qui est comment pouvons-nous retourner des valeurs à partir de cela ? Donc ça va être comme si on avait des fonctions régulières. Donc, renommons ça de l'impression bonjour pour la rendre seule. Et cela va plutôt revenir bonjour. Et donc pour obtenir le résultat,
tout comme avec une fonction régulière, nous appelons notre retour bonjour. Mais maintenant, parce que c'est une fonction asynchrone, nous devons l'attendre. Et une fois cette fonction terminée, nous obtenons la valeur de retour ici. Et puis on pourra l'imprimer. Donc ça va faire exactement la même chose. C' est juste ici. Nous ne l'imprimons pas en interne, mais au lieu de retourner une valeur de la fonction comme celle-ci, et vous remarquerez que la principale différence à une fonction régulière est l'asynchrone et attend. Donc on pourrait faire la même chose ici, comme ça. Et ce serait juste un appel de fonction régulier. Et nous pouvons obtenir la valeur retournée d'ici comme nous le ferions normalement. Mais ce que nous ne pouvons pas faire, nous ne pouvons qu'attendre les routines co. Donc, cela va causer une erreur pour nous, comme nous le verrons dans une seconde. Et autre chose que nous ne pouvons pas faire, c'est que nous ne pouvons pas. Si nous supprimons ceci et supprimons ceci un poids, nous pouvons utiliser un mot-clé wait à l'intérieur d'un non et non à l'intérieur d'une co-routine. Nous devons donc avoir cette définition asynchrone en face pour pouvoir attendre en interne. Donc, nous ne pouvons pas utiliser wait sans avoir un def asynchrone en dehors de celui-ci. Et si nous avons une définition asynchrone def asynchrone, nous devons attendre la réponse parce que sinon, fondamentalement, vous créez un objet co-routine ici, mais il n'a jamais été planifié, il n'a jamais été absent, donc il n'a jamais été exécuté, n'a jamais été ajouté à la boucle d'événement. Donc, soyez juste conscient de ces choses que si vous utilisez async, vous devez toujours attendre cette réponse. Et l'appel d'attente ici ne bloque pas. Cependant, il arrêtera la poursuite de l'exécution de la fonction et redonnera le
contrôle à la boucle d'événement afin que d'autres équipes puissent s'exécuter en attendant. Donc avec ça, je sais que c'est un peu déroutant. La première fois que nous parlons de tout ça et il y a des termes bizarres qui apparaissent. Mais au fur et à mesure que nous suivrons les prochaines conférences, j'espère que vous aurez une compréhension plus claire de la façon dont tout cela fonctionne. Et probablement aussi avec le temps, cela deviendra un peu plus confortable pour vous.
23. Tâches Asynchrones: Donc la prochaine chose que nous allons examiner maintenant est de savoir comment nous pouvons créer des tâches qui sont, eh bien, nous verrons. Donc, la première chose que nous avons remarqué la dernière fois est bien que nous utilisions des fonctions asynchrones ici, et nous pouvons également revenir à l'asynchrone def et peut-être simplement retourner ceci à une instruction print hello. Comme ça. Nous venons d'imprimer bonjour et tunnel. Même si nous utilisons cette syntaxe asynchrone, l'exécution que nous obtenons est toujours essentiellement synchrone car il n'y a rien d'autre que, vous savez, le contrôle peut aller. Donc, bien que nous utilisions cette syntaxe asynchrone et que notre contrôle soit rendu à la boucle d'événement. n'y a rien d'autre prévu qui puisse continuer. Et donc il n'y a rien d'autre qui puisse être travaillé pendant que nous attendons une réponse. Donc de même, si nous avons eu un autre appel de sommeil ici, eh bien, remarquez que
nous, nous obtenons toujours cette exécution synchrone de recyclage va commencer à dormir, va dormir pendant cinq secondes. Et puis on va passer au point suivant. Et nous voilà pour dormir. Nous allons attendre la réponse ici. Et puis, bien que l'exécution ait été rendue, il n'y a rien d'autre qui puisse continuer. Et à ce stade, bien que l'exécution soit rendue à la boucle d'événement, encore une fois, il n'y a rien qui puisse être poursuivi parce que la seule chose qui ne
peut pas continuer l'exécution de ce bloc de fonction, parce que nous sommes qui attendent toujours cette réponse ici. Et il n'y a rien d'autre qui est prévu comme ça peut être travaillé sur. Donc, en général, ce que nous pouvons avoir, c'est que nous pouvons réellement commencer à créer des tâches. Ainsi, nous pouvons avoir plusieurs tâches dans notre boucle d'événements qui peuvent être travaillées pendant que les choses sont attendues. Voyons donc un exemple de cela. Créons une tâche. Et nous allons le faire en allant dans un panneau d'évier. Et nous allons appeler ici créer une tâche. Et je vais prendre ce deuxième appel de sommeil asynchrone. Et je vais ajouter la tâche et ici. Et puis je vais attendre la tâche plus tard. Donc, ce qui se passe lorsque nous créons une tâche, c'est que nous planifions cette co-routine pour qu'elle soit travaillée chaque fois que c'est pratique. Mais jusqu'à ce que nous l'attendions, il n'
y a pas d'arrêt dans le flux de notre routine pour s'arrêter à ce moment-là. Donc, ce que nous obtenons à ce stade, c'est de nous souvenir avant que nos deux couchages qui se passent l'un après l'autre. Dans ce cas, nous avons ajouté une autre tâche. Et donc si nous réexécutons ça, nous verrons maintenant que nous en avons deux avant le sommeil qui se passe. Et puis, oups, j'ai une erreur de syntaxe ici. Je dois enlever l'appel de fonction parce que c'est un objet que nous attendons, pas une fonction ou une méthode de co-working, parce que nous avons déjà appelé la fonction. Donc on a juste un coach, un objet qui va nous retourner. Mais de toute façon, on attend toujours ça. Mais nous remarquerons ici que nous dormons maintenant une fois et nous dormons maintenant à nouveau. Et puis nous commençons ça deux fois, puis nous sommes dans la période de temporisation, et ensuite nous sommes après notre sommeil. Donc, si nous importons le module de temps, alors qu'avant nous l'exécutions, c'est toujours séquentiellement. Donc, nous pouvons avoir un temps de départ ici, ce qui va être notre temps.Deltatime. On peut imprimer ici. Le temps total sera le temps, le temps moins le début. Donc, nous remarquerons que notre exécution ne sera pas aux alentours de 10 secondes, qui est ce que nous avons eu quand nous dormions deux fois de suite, mais plutôt à 5 secondes. Nous avons donc créé cette tâche supplémentaire. Ensuite, quand nous entrons dans l'appel d'attente, nous avons maintenant une autre co-routine que nous pouvons aller
à l'endroit où une autre tâche peut également être exécutée. Et donc dans ce cas, nous avons en fait deux choses exécutées en même temps où je suis, où le contrôle peut être rendu à la boucle d'événement. Et les choses sont planifiées pour fonctionner de manière asynchrone, mais essentiellement simultanément. Donc, si nous ajoutons juste un numéro supplémentaire ici et que nous pouvons imprimer pour comprendre, vous savez, où nous sommes dans chacun d'eux. Nous imprimons n ici, et nous imprimons n ici, et puis ici nous voulons en ajouter un. Ce sera la tâche que nous créerons et planifierons. Et puis ici, nous pouvons en ajouter deux. Donc si on s'en sort, on peut voir que, d'abord, on replanifie cette tâche, mais on attend cet appel ici, qui vient ensuite à ça. Et c'est là que notre exécution
s'arrête ici parce que nous attendons juste la réponse ici. Nous avons donc redonné le contrôle à la boucle d'événement. Et maintenant, nous avons une autre tâche qui a été planifiée. Et maintenant comme un moment pratique pour travailler dessus parce que rien d'autre n'est travaillé sur. Et donc cette tâche est maintenant fondamentalement comme nous pouvons le voir ici, commence à être exécutée une fois que nous atteignons ce point d'attente ici. Et puis nous finissons, ou notre premier Coubertin se termine ici. On voit que l'exécution revient à cette routine après avoir franchi cette étape. Et puis nous attendons le résultat de cette tâche ici. Et maintenant, nous n'
exécutons plus ce bloc de routine tant que nous n'aurons pas la réponse ici, c'est pourquoi nous avons cet appel ici. Et ensuite, nous évaluons la réponse de ceci, c'est pourquoi nous avons le bonjour ici. Si nous retournons l'ordre d'exécution ici, vous remarquerez que l'ordre que nous avons imprimé
là-bas ya aussi changement aura le salut second dernier, et ensuite nous aurons l'après sommeil à cause de la ordre des déclarations d'attente ici. Donc, nous pouvons voir maintenant que nous entrons dans cette nature plus simultanée parce que maintenant nous avons en fait plusieurs routines co différentes qui fonctionnent en même temps. Dans ce cas, c'est juste aussi. Mais comme vous le savez, une co-routine est en quelque sorte à la place de juste attendre un résultat et il redonne le contrôle à la boucle d'événement. Il peut en fait continuer et vous pouvez commencer à travailler sur d'autres tâches jusqu'à ce qu'elles soient, il atteint ce point d'attente. Et puis une fois qu'une autre co-routine sera terminée, l'exécution ou le contrôle de l'exécution sera remis à cette co-routine.
24. Méthode de collecte Async: Très bien, donc nous avons maintenant vu notre premier exemple de la façon dont nous avons cette exécution simultanée en ayant des tâches planifiées. Et alors qu'une co-routine attend essentiellement une réponse, l'exécution d'une autre peut continuer, qui est ce que nous avions quand nous avons planifié une tâche ici. Et puis l'exécution d'une sorte de s'est produite quand c'était commode, quand rien d'autre n'était travaillé sur. Mais nous avons encore ce problème ici où, par exemple, nous avons cette déclaration de bonjour d'impression. Et celui-ci est toujours attendu après cela,
seulement après que ce sommeil se termine ici. Et sachez idéalement, nous ne voudrions pas qu' idéalement ces deux-là puissent réellement courir en même temps. Donc, par exemple, disons que nous avions deux
appels d'API ici qui ne dépendaient tout simplement pas les uns des autres. Donc, ceci ici frappe l'API un et ceci ici frappe API à Nous de toute façon, même si nous l'avions
comme, comme ceci, ou si nous l'avions comme avant, cela ne fonctionne toujours pas comme nous le voulions
parce que nous attendons fondamentalement la réponse d'un appel d'API. Et puis nous allons le faire,
alors nous allons seulement lancer l'appel de la seconde, qui n'est pas ce que nous voulons. Nous voulons qu'ils soient essentiellement à la fois le début presque immédiatement, l'un après l'autre, et ensuite nous voulons que ce délai d'attente se chevauche de sorte que tout ce temps d'attente réseau ne se passe essentiellement pas séquentiellement, mais cela se passe presque à en même temps. Quoi qu'il en soit, peu importe comment nous retournons cet ordre, nous n'y arriverons pas vraiment. Alors, comment pouvons-nous faire quelque chose comme ça ? Eh bien, nous pouvons utiliser quelque chose d'autre de l'E/S asynchrone, qui est appelé rassembler. Donc, nous pouvons aller dans les E/S asynchrones et ici nous pouvons utiliser ceci et la méthode de collecte. Et ici, nous pouvons maintenant mettre une série de coroutines et ils seront essentiellement tous programmés et exécutés simultanément. Donc nous n'avons pas celui-ci après l'autre, mais ils sont tous programmés en même temps. Et n'importe lequel, vous savez, quelle que soit la fin et quel ordre. Fondamentalement, on peut en quelque sorte passer à travers ça. Il y a encore un certain ordre que nous avons ici, c'est l'ordre dans
lequel nous les avons mis. Mais nous sommes maintenant en mesure d'exécuter tout cela simultanément et comme nous le voulions. Alors voyons cela en action. Comment ferons-nous ça ? Eh bien, nous pouvons avoir, par exemple, sont la première co-routine ici, qui va être notre asynchrone. Nous allons avoir notre deuxième co-routine, qui est le sommeil 2 de l'ordinateur Eysenck. Et puis nous allons avoir notre troisième,
qui va imprimer à partir de bonjour. Nous pouvons maintenant supprimer la planification de cette tâche. Et si nous faisons ça maintenant, nous remarquerons que nous allons aller dans celui avant le sommeil, qui est là. Ensuite, on va aller dans l'avant de dormir aussi, qui est ici. Ensuite, nous avons notre empreinte faible parce que ces deux routines co sont, ils ne bloquent pas mais ils sont essentiellement en attente d'une réponse. Et pour qu'ils puissent redonner le contrôle à notre boucle d'événements. Donc, nous continuons ici, nous exécutons ceci, nous donnons ce contrôle à la boucle d'événement. Nous exécutons, nous partons et nous exécutons, nous arrivons ici, nous reprenons le contrôle. On y va, il y a des finis de routine parce qu'il n'y a jamais d'attente. Et puis nous pouvons revenir à la boucle d'événement et au poids de la boucle d'événement. Et puis il verra parce que celui-ci était prévu en premier et ils dorment pour le même temps. Nous venons d'abord ici. Et donc nous pouvons continuer avec l'exécution de ceci jusqu'à ce que, eh bien, notre co-routine se termine ici. Et puis le contrôle donne, donné à la boucle d'événement et puis nous voyons ce qui se passe d'autre. Donc nous avons celui-ci ici, qui se termine ensuite. Alors mettons à jour ceci un peu et dormons aussi pour cette quantité de temps. Nous verrons que l'ordre de planification est une sorte de ce que nous avons ici, mais l'ordre de finition peut ne pas vraiment être comme ça. Donc, dans ce cas, nous allons nous attendre à ce que celui-ci soit programmé en premier. Ensuite, nous reprendrons le contrôle. Une fois que nous aurons atteint ce point, alors nous pourrons commencer à courir. Celle-ci ici. Rendait le contrôle. Nous avons atteint ce point, nous pouvons exécuter celui-ci. Nous avons terminé toute la co-routine, et maintenant nous revenons à notre boucle événementielle. Et à ce stade, celui-ci finira d'abord à l'avance parce qu'il dort plus lentement, pendant moins de temps. Pour qu'on puisse revenir à celui-ci. Je termine cette co-routine parce qu'il n'y a rien d'autre après le sommeil, après cette déclaration imprimée. Et ensuite, nous avons la seule co-routine qui attendait, qui va être celle là. Donc, si nous exécutons ceci, nous pouvons voir que l'ordre dans lequel ils finissent points,
fondamentalement, nous pouvons alors continuer avec l'exécution de ceux-ci. Et donc avec cela maintenant, nous avons une nature beaucoup mieux simultanée parce que nous sommes capables, plutôt que d'avoir toutes ces instructions p séquentielles, au lieu de cela, nous les avons toutes sortes de fonctionner simultanément et nous les démarrons. Et chaque fois que nous frappons cette attente de 0,1 co-routine, nous pouvons fondamentalement redonner le contrôle et une autre co-routine peut continuer à courir. Et si nous avons donné par Control T, petit t, puis boucle et tout est en quelque sorte en cours d'exécution. Dès qu'une chose finira, on pourra y aller et continuer avec l'exécution de ce Coubertin en obtenant cette nature plus agréable que nous recherchons. Donc, à ce stade, vous pouvez vous demander, eh bien, quelle est la différence entre async et threading ? Donc, en général, et si vous vous souvenez de ce dont
nous avons parlé au tout début, notre asynchrone ici, cela fonctionne sur un noyau et aussi n'importe quel thread et tout est fait à travers ces boucles d'événements planifiées où nous avons un moyen de les taureaux et fondamentalement les futurs qui représentent qu'une réponse va venir. Mais ce n'est pas encore là. Alors qu'avec le thread, nous créons en fait plusieurs threads différents et il y a aussi des frais généraux associés à cela. Alors qu'ici, nous sommes juste dans un seul fil et nous avons en fait moins de frais généraux. Maintenant, en général, quand utiliseriez-vous l'un ou l'autre de ces deux ? Eh bien, vous le feriez ou je l'utiliserais généralement lorsque nous
construisons des programmes comme des travailleurs comme nous l'avons fait dans notre module de thread, où nous avions beaucoup de travailleurs différents accomplissant des objectifs différents. Alors que si vous avez juste des tâches individuelles, comme nous avons plus dans ces cas, alors vous pouvez aller à un synchrone. Évidemment, si vous vous sentez beaucoup plus à l'aise avec l'un ou l'autre, vous aurez probablement tendance à aller vers ces choses et vous pouvez probablement voir atteindre une concurrence similaire. Bien que rappelez-vous simplement qu'avec Async vous faites juste un seul cœur, seul thread, alors qu'avec le thread, vous faites plusieurs threads simples. Donc, il y a cette différence là et il y a aussi des frais généraux associés au filetage. Mais évidemment, vous savez, ça se résume aussi un peu à réconforter. L' autre chose est que dans les applications Web, beaucoup de fois vous allez utiliser asynchrone. Et il est donc très habituel d'avoir définitions
asynchrones et de points où vous pouvez ensuite masquer le point de terminaison et qui devient plus chaud à la boucle d'événement afin que vous connaissiez vos différents points de terminaison et votre serveur en général est ne bloque pas l'exécution parce qu'il essaie d'exécuter des choses en parallèle. Donc asynchrone, c'est en quelque sorte le résumer. Généralement, de mon point de vue, utilisé beaucoup pour les tâches ainsi que le développement web. Alors que le filetage, j'utiliserais beaucoup plus pour les travailleurs de la construction comme des programmes comme nous l'avons fait dans notre plus grand module de tournage.
25. Utiliser les Timeouts Async: Maintenant, en général, quand nous avons affaire à une communication réseau ou à une sorte d'Io, il peut y avoir des problèmes ailleurs qui peuvent causer sorte d'interruption ou, fondamentalement, certaines choses peuvent prendre beaucoup plus de temps. Par exemple, si un serveur est surchargé ou ne répond pas actuellement ou très lent, si nous essayons d'envoyer un ping à ce serveur et qu'il nous faut une éternité pour obtenir une réponse. Alors même si nous utilisons une sorte d'exécution simultanée comme nous l'avons ici, il peut y avoir un straggler qui prend tout et ralentit le parce que nous attendons que cette seule chose se termine. Il y a donc une bonne méthode que nous pouvons utiliser pour cela. Avoir une sorte de limites quant au temps que nous voulons attendre les réponses. nous savons généralement à quel point les points de terminaison réagissent plus rapidement, ainsi qu'à quel degré de variabilité nous avons. Et nous savons qu'avec une très grande certitude, nous sommes en mesure d'obtenir des réponses et moins que cette période de temps. Et la période de temps est un bon moment ici à utiliser. Nous pouvons également utiliser quelque chose appelé le timeout. Donc, nous pouvons faire, par exemple, est que nous pouvons dire point d'E/S asynchrone attendre. Et cela signifiera essentiellement que nous allons attendre autant de secondes. Et si notre co-routine ne se termine pas à ce moment-là, alors nous allons soulever une exception de délai d'attente pour cela. Disons qu'on veut lui donner cinq secondes. Et nous allons aussi envelopper cela dans un essai et sauf déclaration où nous allons spécifiquement attraper un délai d'attente Aram. Et ici, nous allons imprimer l'erreur de délai d'attente rencontré. Donc, dans ce cas, si nous lançons ça, tout va bien se passer parce que ça prend deux secondes et pas de limite de temps, c'est cinq secondes. Mais si nous passons à, disons trente secondes, comme si quelque chose fonctionnait vraiment lentement ou il y a juste une fenêtre de délai d'attente de 30 secondes et ce n'est pas réactif. Et nous gardons cette connexion là et nous attendons une réponse, mais ça ne répondra jamais. Et la connexion sera juste interrompue après, disons, 30 secondes. Si on attend cinq secondes, alors après avoir atteint la cinquième seconde, on va juste tuer ça. Et nous allons plutôt arriver à une erreur, que nous pouvons voir ici dans une seconde. Nous pouvons donc voir que nous avons rencontré une erreur de délai d'attente. Et parce que nous avons ce composant de timeout ici, maintenant, sachez que parce que nous sommes en quelque sorte confrontés à ce cas d'exception, nous pouvons voir que nous allons dans les dormages avant ici. Et nous avons effectivement entré ce cas d'exception. Donc, les autres routines co que nous avons aussi, comme nous pouvons le voir ici, qui ont effectivement pas la possibilité de terminer parce que nous avons rencontré cette exception avec le poids pour la méthode. Donc, évidemment, cela peut être une chose vraiment agréable à utiliser pour s'assurer que les parties de votre exécution ou non bloquées pendant très longtemps pour des raisons extérieures. Mais évidemment, vous voulez aussi être prudent avec cela car il peut aussi interrompre d'autres choses qui sont en cours d'exécution si elles sont attendues en même temps, comme dans ce cas que nous avons ici.
26. Créer des boucles à Asynchronous: Maintenant, un autre cas que je voulais examiner était asynchrone pour les boucles car il peut parfois voir cela. Mais je veux passer en revue et
regarder fondamentalement le comportement pour nous assurer que nous comprenons exactement
ce qu'est une boucle FOR asynchrone et ce qu'elle fait et ne fait pas. Alors allons de l'avant et modifions notre sommeil asynchrone ici au lieu d'être un générateur, qui va juste donner des valeurs, et ensuite il va dormir. Donc nous allons dire pour moi à portée, et nous allons donner le résultat I. Et ensuite nous allons dormir pendant une seconde. Et disons pour moi entre un et n. Et nous dirons que n est égal à la valeur maximale entre deux extrémités. Et juste pour qu'on fasse quelque chose, non ? Et maintenant, ce que nous pouvons faire est que nous pouvons utiliser une boucle asynchrone pour et nous allons dire pour k dans un sommeil de lavabo 5, et ensuite nous pouvons imprimer k. D'accord, alors allons de l'avant et nous allons aussi parler de ce qui se passe. Donc nous avons eu nos cinq ans comme intrants juste parce que, eh bien, c'est un peu surimpression ici encore. Et puis nous sommes en train de la sélectionner et de nous assurer que c'est au moins deux. Et nous allons dans notre boucle pour ici, et nous partons de un à n. Donc ça va être de un à, mais pas de cinq. Donc, de un à quatre, comme nous le voyons ici. Et puis nous donnons cette réponse, et ensuite nous attendons ce sommeil que nous avons ici. Maintenant, nous pouvons voir passer par ici, ou le temps d'exécution total est d'environ dix secondes. Donc si nous avons un plus deux est trois, plus trois est six, plus quatre est dix. Donc nous sommes toujours en train d'exécuter ça séquentiellement. Nous ne faisons pas cela simultanément, sinon, notre temps d'exécution sera de quatre secondes, puisque donc le sommeil le plus long que nous ayons ici, soit environ quatre secondes. Donc, la chose importante à propos de cette asynchrone pour est que nous avons fondamentalement une autre étape où nous sommes capables de redonner le contrôle à la boucle d'événement. Donc, plutôt que d'avoir une boucle for-où fondamentalement ce genre d'itération se produit, l'avant asynchrone nous donne une autre étape où pendant cette itération, si nous attendons une réponse, nous pouvons à nouveau donner le contrôle à la boucle d'événement puis revenez à notre coroutine une fois que nous serons prêts à poursuivre notre boucle. Donc, c'est juste une chose importante à noter que si vous voyez un plancher asynchrone, si vous pensez à écrire un asynchrone pour, cela ne fonctionne pas. Il ne fonctionne pas simultanément et ne fonctionne pas de manière séquentielle, mais il ajoute fondamentalement une autre étape où nous pouvons redonner
le contrôle à la boucle d'événement afin que d'autres choses puissent continuer à leur exécution.
27. Utiliser les bibliothèques asynchrones: Donc, la prochaine chose que je voulais jeter un oeil est d'
utiliser d'autres bibliothèques avec un traitement asynchrone. Donc, certaines bibliothèques prennent en charge asynchrone et d'autres ne le font pas. Et je veux juste aller de l'avant et regarder ça et vous montrer une comparaison rapide de, vous savez, comment ça ressemblerait. Donc, nous allons utiliser, et j'ai déjà comme un petit chaudron
ici fondamentalement avec quelques URL que j'ai ramassé. Ce que nous allons faire est d'exécuter un programme très simple, était juste pings chacune de ces URL et ensuite obtient juste la réponse de textes à partir de lui. Ça ne fait même pas vraiment quoi que ce soit avec, juste un peu l'avoir. Donc, nous allons écrire ceci de deux façons. L' un d'eux va utiliser la version synchrone allait juste utiliser la bibliothèque de requêtes. Donc tu n'as pas ça. Vous pouvez aller de l'avant et écrire des requêtes d'installation de pip comme ceci. Et puis nous allons également utiliser le HTTP IO, qui va être HTTP comme ce pip installer cela. Et l'un d'entre eux, vous pouvez probablement deviner que ce sera le HTTP va nous
permettre de le faire de manière asynchrone tandis que l'autre est une bibliothèque asynchrone. Donc on va commencer par le synchrone. Nous allons importer des demandes. Et ce qu'on va faire, c'est qu'on va juste courir un peu en boucle. Nous allons dire pour URL. Dans les URL, nous allons appeler les requêtes dot get URL. Et puis nous pouvons chronométrer notre processus ici et nous pouvons dire
notre, notre temps de début .Deltatime et notre temps de fin va être time.Deltatime. Et puis nous pouvons dire que les crêtes ont pris et ensuite nous avons notre temps de fin moins départ. Donc, nous pouvons juste exécuter ceci et cela va juste
être la manière synchrone typique standard. Et nous pouvons voir que ça va prendre quelques secondes,
probablement, disons 3,5 secondes en ce moment. Alors allons de l'avant et écrivons la version asynchrone de celui-ci. Et regardons aussi les composants individuels et la calvitie. Donc nous allons faire face à la mort et nous allons dire obtenir la réponse URL. Nous allons passer ici une URL. Et maintenant, nous allons utiliser notre bibliothèque HTTP AIO que nous venons d'importer ou que nous venons d'installer. Donc, nous allons importer le HTTP E/S comme ceci. Et nous allons dire avec AIO http dot session client. En tant que session, nous allons en faire une largeur asynchrone. Et je parlerai de ça dans une seconde. Et nous allons faire asynch avec session, ne pas obtenir URL comme réponse. Et puis enfin, nous allons retourner un point de réponse de poids txt. Donc nous allons passer en revue chacune de ces lignes dans la seconde. Et ici, bien sûr, nous voulons aussi nous assurer que nous obtenons la réponse des textes. Donc, nous pouvons dire que la réponse de texte de synchronisation va être ceci. Et ici, nous pouvons juste ajouter à notre liste. Et puis nous pouvons faire quelque chose de similaire. Mais ici, nous avons nos tâches. Et pour chacun d'entre eux, vous voulez asynchrone o, nous voulions créer une nouvelle tâche, qui va appeler notre réponse URL GET. On va passer. Ce n'est pas ce que je veux. Bouger du tout. Où sommes-nous ? Ici ? On va l'appeler, passer à travers notre réponse. Nous allons fournir notre URL en tant qu'entrée ici. Et puis nous allons attendre le point d'E/S asynchrone. Et nous allons cliquer dans toutes nos tâches et
décompresser toute cette liste pour les fournir en tant qu'arguments individuels. Et puis notre réponse textuelle asynchrone va être la sortie que nous obtenons de cela. Et puis ici, nous pouvons dire que les requêtes asynchrones ont pris cela. Maintenant, allons-y et exécutons ça. Et puis allons de l'avant et revenons à cette méthode ici. Nous sommes de retour à cette co-routine plutôt que de comprendre ce qui se passe exactement. Donc, exécutons ceci pour que nous puissions réellement comparer les performances. Donc nous avons notre processus synchrone en cours. Oh, j'ai oublié d'initialiser notre objet ici. Alors allons-y et courons ça une fois de plus. On y va. Donc, avec notre processus synchrone, nous avons pris un peu plus de trois secondes, et avec notre processus asynchrone, nous avons pris environ une seconde. Alors allons-y et jetons un coup d'oeil à ça ici. Donc, ce qui se passe comme nous avons plusieurs rythmes différents, donc si vous avez programmé en Python pour un peu, vous êtes probablement familier avec l'instruction, avec, qui est fondamentalement que nous créons quelque chose comme un contexte ou un raisonnement ou Context Manager, qui gère essentiellement la création ainsi que le démontage de tout ce que nous avons et nous n'avons pas à nous soucier de fermer quelque chose. Nous avons pu l'utiliser dans ce contexte avec la déclaration ici. Maintenant, l'asynchrone avec que nous voyons ici deux fois. Chacune de ces fois, nous donnons essentiellement l'opportunité de la boucle d'événement. Deuxièmement, nous redonnons le contrôle à la boucle d'événement et nous donnons occasion de commencer ou de continuer avec d'autres tâches. Donc, fondamentalement, nous avons trois instances, une avec le poids et les deux autres avec nos gestionnaires de contextes asynchrones ici, où nous redonnons le contrôle à la boucle d'événement afin qu' elle puisse potentiellement continuer avec autre chose. Il y a donc beaucoup de remise du contrôle à la boucle d'événement qui se passe ici. Cela le rend vraiment agréable et comme asynchrone, et surtout avec ces différentes parties. Donc, l'un d'entre eux recevrait une session de notre pool de sessions. Ensuite, le suivant serait réellement effectuer les demandes, ce qui impliquerait beaucoup de l'attente du réseau. Et puis l'autre composant sortirait réellement la réponse HTML complète, parce que nous ne l'avons peut-être pas toujours. Et donc nous devons rassembler toutes ces données et les analyser en une variable. Et il y a aussi un peu de temps d'attente ici. Donc, pour chacun de ces composants où nous
pouvons effectivement avoir une sorte de composant d'attente. Nous redonnons essentiellement le contrôle de la boucle d'événement jusqu'à ce que nous soyons prêts à continuer avec cela. Donc, il y a beaucoup d'asynchrones ou il y a beaucoup de redonner le contrôle à la boucle d'événement. Ces différents appels que nous faisons ici, en
gros, nous le faisons trois fois. Alors que pour nos demandes, évidemment, la bibliothèque des requêtes elle-même. Où sommes-nous ? On y va. Donc, cela lui-même est juste un peu d'un appel bloquant. Et il n'y a pas, il n'y a pas d'obtention asynchrone d'une session à partir d'un pool. Nous n'utilisons pas non plus actuellement les sessions dans ce cas. Nous ne
recevons pas la demande de manière asynchrone, vous savez, comme nous le serions dans ce cas. Et nous n'avons pas non plus une sorte asynchrone d'obtenir ces données HTML et de les rassembler en arrière-plan, puis continuer et nous sommes prêts pour cela. Maintenant, bien sûr, nous pouvons optimiser cela un peu et nous pouvons mettre ce auto dans comme un def asynchrone, obtenir des URL avec des requêtes, et nous allons mettre l'URL ici. Et là, nous pouvons le faire ici, nous pouvons juste le rendre. Mais comme vous le remarquerez probablement aussi dans une seconde, si nous avons nos tâches ici et que nous planifions ces tâches. Donc, nous allons dans un évier, io dot créer des tâches et nous allons tester des stylos. Et si nous voulons créer cela comme une tâche, passant le paramètre URL, il n'y a toujours pas d'appel d'attente nulle part. Donc, même si nous essayons d'utiliser cette méthode asynchrone d'asynchrone, je sais que Don collecte, et nous essayons juste d'exécuter toutes ces tâches de manière asynchrone. Et quelque part ici, nous devrions avoir notre réponse texte, je pense qu'il a été appelé. Donc, même si nous avons essayé d'utiliser cette approche, nous n'en obtiendrons aucun avantage de performance car
il n'y a aucun appel d'attente nulle part. n'y a aucun point où nous retournons le contrôle à la boucle d'événement. Donc, même si nous essayons d'envelopper cela comme une fonction asynchrone, comme nous pouvons le voir ici. Tout cela est un processus synchrone et il est complètement bloquant. Alors que dans notre processus asynchrone, nous avons fondamentalement ces différentes opportunités et obtenir la session à partir
du pool, l'exécution réelle de la requête, ainsi que l'analyse de la réponse de texte pour obtenir un texte réponse sur. Chacun de ces trois composants nous permet essentiellement de redonner le contrôle à la boucle d'événement afin que d'autres choses puissent se produire simultanément ou pendant que cette chose attend à la place. Alors que dans notre cas synchrone, nous n'avons pas l'occasion de le faire et nous sommes essentiellement
bloqués jusqu'à ce que cette requête l'envoie, obtienne la réponse, analyse la réponse du texte. Donc, tout cela est un processus de blocage. Donc, comme nous pouvons le voir, il y a de grands avantages que nous pouvons réellement obtenir de l'utilisation de requêtes asynchrones évidemment. Mais nous devons faire attention à utiliser également la bibliothèque asynchrone appropriée. Donc, dans ce cas, ce sera un HTTP 0 pour l'entrée et la sortie du fichier. Il y a aussi quelque chose
qui s'appelle le fichier AI, que vous pouvez utiliser où vous pouvez rendre la lecture et l'écriture de fichiers, ainsi que des opérations générales de fichiers sorte asynchrone comme ceci. Il y a aussi d'autres choses comme les connexions aux bases de données. Il y a beaucoup de bibliothèques asynchrones que vous pouvez réutiliser pour cela. Mais vous devez vous assurer que si vous essayez de rendre cela asynchrone, vous devez également utiliser les bibliothèques appropriées qui supportent cette manière asynchrone. Sinon, vous allez juste avoir des composants de blocage parce que c'est un processus synchrone et qu'aucun contrôle n'est rendu à la boucle d'événement.
28. Déclaration Async Async: Bon, donc nous avons vu des trucs plutôt cool en ce moment avec des processus asynchrones. Mais allons de l'avant et regardons une chose de plus cool, qui va attendre que certaines coordonnées soient
terminées ou que certaines tâches soient terminées et ensuite traiter avec celles-ci et sorte de faire cela itérativement. Parce que actuellement, ce que nous avons vu avec la collecte, c'est que nous attendons essentiellement tout pour terminer. Ce qui veut dire que si nous avons un tas de choses qui ne prennent peu de temps et que l'un d'eux est un traître. Cela peut évidemment aussi ralentir notre programme. Donc, je vais à nouveau importer les E/S asynchrones. Je vais avoir mon si nom est égal à principal. Et ici, je vais juste au point d'E/S asynchrone, exécuter notre co-routine principale, et allons de l'avant et trouver ça. Je vais écrire. Et je vais aussi utiliser le sommeil à nouveau. Donc nous allons aller dans le def asynchrone et nous appellerons ceci notre sommeil asynchrone à nouveau. Et là, nous allons avoir un périmètre. J' ai juste combien de temps on va dormir. Ou si nous le voulons, nous pouvons le voir un peu plus explicite à leur sujet et l'appeler quelque chose comme une durée. Et puis nous dirons que nous allons attendre le sommeil des points d'E/S asynchrones pour la durée. Et puis nous allons juste retourner la durée. Juste pris, ont aussi quelque chose de retour de là. Très bien, donc dans notre Coroutine principale,
ce que je veux faire, c'est planifier 10 tâches. Et à chaque fois que l'un d'eux se termine, je veux pouvoir les traiter. Donc, ce que je vais faire, c'est que je vais avoir une variable ici appelée en attente. Et vous verrez pourquoi dans une seconde, que je vais initialiser pour être juste un ensemble vide. Ensuite, je vais itérer pour moi dans la gamme un à 11. Et pour chacun d'entre eux, je vais ajouter un élément. Et nous allons dire tâche de création de point d'E/S asynchrone. Nous allons donc créer notre sommeil asynchrone avec la durée spécifique. Donc en ce moment et nous avons vu la tâche de création avant. Nous sommes juste en train de créer un tas de tâches que nous ajoutons dans cet ensemble ici que nous avons appelé en attente. D' accord ? Donc maintenant, nous pouvons utiliser quelque chose appelé Async, IO point d'attente. Et ici, nous pouvons fournir un intervalle de tâches. Ainsi, par exemple, un ensemble ou une liste de tâches. Et, et nous pouvons avoir un comportement différent pour ça, qui est ce que nous allons regarder dans une seconde. Donc, gardons juste un peu avec le comportement par défaut pour l'instant. Donc, nous allons avoir notre premier intervalle de tâches, ce qui est juste l'attente que nous avons ici. Et le retour que nous obtenons réellement de lui. Les variables sont appelées faites ainsi qu'en attente. C' est donc pour ça que nous avons ce nom de variable ici. Parce que les réponses que nous obtenons sont en fait divisées en deux choses. Donc, ceux-ci sont les tâches qui ont terminé et le jaune, les tâches qui sont toujours en attente. Donc nous allons laisser ça comme ça pour l'instant. Et puis nous allons juste imprimer sont faites des tâches. Et nous imprimerons également nos tâches en suspens. Et en laissant ça comme pour le moment et nous y apporterons d'autres changements dans une seconde. Allons-y et courons ça d'abord. Et oui, allez-y et appuyez sur Entrée. Cela devrait prendre environ 10 secondes. Je n'ai pas vraiment d'impression supplémentaire ici, malheureusement en ce moment, sauf pour sont fait et en attente à la fin ici. Mais on y va. Nous avons donc notre premier jeu de résultats, qui va être celui-ci ici. Et nous pouvons voir que nous avons un ensemble qui a la tâche, ainsi que le résultat qui est venu avec elle. Et puis nous avons enfin aussi cet ensemble vide ici, qui est fondamentalement les tâches restantes en attente. Donc, nous avons quelque chose de cool, mais essentiellement ce que nous avons en ce moment est peu la même chose que nous avons déjà avec le rassemblement en essence parce que nous attendons toujours que tout se termine. Il y a donc différentes façons d'y arriver. Une des choses que nous pouvons faire est que nous pouvons ajouter quelque chose comme un délai d'attente. Maintenant, cette fois est différente de ce que nous avions pour le poids, dans ce cas, nous vérifions essentiellement ou nous allons essentiellement obtenir notre résultat ici pour Don et Pending une fois que nous atteindrons cette limite de délai d'attente. Mais cela ne signifie pas que nos tâches planifiées actuelles vont être annulées. Cela veut juste dire que nous allons obtenir notre réponse à ce moment-là. Donc, ce que nous pouvons faire, c'est que nous pouvons dire, alors qu'il y a encore des tâches en suspens. Donc, alors que la longueur de notre ensemble en attente est supérieure à 0, nous allons aller de l'avant et imprimer ceci. Donc si nous faisons ça, maintenant, nous devrions le voir imprimer toutes les deux secondes, qui est ce que nous avons ici. Évidemment, il y a beaucoup de spam à notre sortie comme nous pouvons le voir, parce que c'est très verbeux. Chacun de ces éléments, il y a beaucoup de détails, mais nous pouvons voir l'ensemble que nous avons pour ajouter des résultats est fondamentalement en quelque sorte juste de diminuer continuellement en taille. Et donc toutes les deux secondes, nous revenons en quelque sorte et nous voyons quels résultats sont déjà terminés. Alors ce qui est en est fait. Et puis nous continuons simplement avec les tâches en attente actuelles. Maintenant, évidemment, si vous voulez obtenir des résultats, nous voulons probablement aussi le faire. Et donc nous pouvons réellement itérer plus sont des tâches faites. Et nous pouvons dire pour les tâches accomplies, portail dire pour Don tâche et fait si vous voulez obtenir le résultat, nous pouvons juste
attendre, attendre cet élément ou nous pouvons attendre cette tâche. Et à partir de là, nous pouvons obtenir le résultat que nous avons ici. Alors allons-y et courons ça une fois de plus. Donc, nous allons voir essentiellement l'ordre lequel nous nous attendions à ce que ces tâches se terminent. Donc nous pouvons voir ici que toutes les deux secondes, essentiellement, nous arrêtons ceci ou nous atteignons un délai d'attente pour notre Coubertin ici et nous recevons les réponses. Mais ces tâches ont toujours été planifiées et elles ne sont pas techniquement et progressent comme nous pouvons le voir, parce que c'est toutes les deux secondes que nous obtenons les réponses. Et nous pouvons ensuite les boucler. Et si nous utilisons cette attente, nous pouvons obtenir le résultat réel comme celui-ci. Mais évidemment c'est, c'est assez sympa parce que maintenant nous n'avons pas à attendre que tout se termine, mais nous pouvons une sorte de processus en morceaux comme il se termine. Et bien sûr, quelque chose que nous pouvons aussi faire est que nous pouvons ajouter plus de choses à la liste en attente ou à l'ensemble en attente dans ce cas. Donc, ce que nous pourrions faire, par exemple, c'est que nous pourrions, vous savez, en bas, juste, nous avons plus de tâches à ajouter. Je vais juste faire un très simple juste ajouter une tâche qui dort une fois. Et on dira qu'on fera ça une fois. Ajouter une tâche est égal à false. Et puis nous dirons, si cette tâche était vraie, si ajouter une tâche, alors nous voulons ajouter la tâche et nous allons juste définir cette variable sur false. Donc, c'est juste infiniment et fondamentalement rester coincé dans cette boucle. Mais le point que j'essaie de faire avec ceci est que nous pouvons simplement continuer à ajouter plus de tâches dans ce cas sont en attente ensemble. Cela nous donne donc beaucoup plus de flexibilité, car au fur et à mesure que les choses arrivent, nous pouvons continuer à créer et planifier ces tâches. Et nous pouvons obtenir ces réponses chaque fois qu'elles sont
prêtes à utiliser ce poids de point d'E/S asynchrone. Dans ce cas, nous utilisons un délai d'attente spécifique, mais il existe également une méthode différente à notre disposition. Et ce paramètre est appelé retour quand. Et ici, nous pouvons avoir différentes options. La valeur par défaut, je pense, est entièrement terminée, écrite dans toutes les majuscules. Donc, si nous ne définissons pas de délai d'attente, nous n'obtiendrons notre réponse qu'une fois toutes les tâches terminées. Et c'est un peu ce que nous avons vu au tout début quand nous n'avons pas fourni ce paramètre, que nous attendons en quelque sorte que tout soit terminé. Donc, on verra un à 10 imprimés. Et quand on l'ajoutera, on en verra un autre à la toute fin ici. Et nous pouvons voir qu'en gros, nous attendons que tout soit fini. ne s'agit pas d'une commande car les ensembles ne sont pas commandés. Donc, nous sommes juste en quelque sorte d'obtenir toutes les tâches accomplies comme nous avons ici. Mais nous pouvons aussi changer cela, mais nous ne le sommes pas si nous ne voulons pas vraiment utiliser un délai d'attente non plus parce que peut-être vos tâches vont réellement se terminer extrêmement rapidement et nous ne sommes pas vraiment sûrs de ce qu'il faut utiliser là-bas, ou nous Je veux le faire comme les tâches finissent. Nous pouvons également utiliser la déclaration de retour un à remplir pour la première fois. Cela signifie que chaque fois que quelque chose se termine, alors nous sortons de cette co-routine ici et pouvons continuer avec le reste. Donc, dans ce cas, nous allons voir ces numéros imprimés un par un dans l'ordre. Comme on peut le voir ici. C' est parce que chaque seconde de nos coroutines, c'est en fait une de nos tâches, elle est en train de s'achever. Donc, nous pouvons voir que c'est en fait aussi vraiment, vraiment cool chose à faire. Parce que par rapport à toutes les autres choses, vous savez, nous pouvons rencontrer des problèmes là-bas où, fondamentalement, vous savez, si une chose prend beaucoup, beaucoup plus de temps à courir que tout le reste, alors nous allons toujours passer beaucoup de temps en attente. Et donc cette co-routine de pondération que nous avons à notre disposition nous
permet en fait beaucoup plus de flexibilité dans ce sens pour vraiment obtenir deux choses, soit quand elles sont prêtes ou aussi dans un intervalle de temps spécifique afin que nous puissions continuer le traitement des choses qui sont faites. Et nous pouvons également ajouter plus de tâches afin qu'ils aient également commencé
à travailler pour vraiment obtenir un programme beaucoup plus dynamique et encore plus simultané.
29. Combiner Async et multitraitement: Bon, maintenant je veux jeter un oeil à la façon dont on peut combiner multitraitement et programmation asynchrone. Parce que précédemment, nous avons parlé que nous ne pouvons avoir qu'une seule boucle d'événement par thread. Mais quelque chose dont nous devons nous souvenir en Python est que nous avons aussi cette chose appelée un verrou d'interpréteur global, qui limite fondamentalement la concurrence réelle que nous pouvons obtenir. Mais heureusement, quand nous faisons le multitraitement, nous avons en fait un Gill par processus. Donc, nous pouvons faire beaucoup d'utilisation du matériel complet disponible pour nous, ainsi que certaines des limitations de la concurrence de Python
en utilisant le multitraitement et la combinaison avec asynchrone. Donc, nous allons aller de l'avant et importer des E/S asynchrones. Et nous allons également aller de l'avant et importer le multitraitement. Et nous allons en avoir si le nom est égal à l'appel principal. Mais pour l'instant, nous allons simplement transmettre ça. Et maintenant ce que je vais faire, c'est que je vais définir une classe appelée multitraitement asynchrone. Et cela va hériter du multitraitement, ne pas traiter. Et ce que ce cours va faire, c'est qu'il va créer un processus pour nous. Et dans ce processus, nous allons ensuite démarrer notre boucle d'événements asynchrone. Donc, nous allons aller de l'avant et appeler l'initialisation et juste initialiser la classe parent. Et nous allons également fournir comme paramètres certaines durées parce que ce que nous allons faire est que nous allons juste
émuler une sorte de minuteur d'E/S réseau longue durée ou juste un autre temps d'E/S pour simplement utiliser la co-routine de sommeil à nouveau. Donc, nous allons avoir notre asynchrone défini. Et on appellera ça le sommeil asynchrone. Et ici, nous pouvons passer dans la durée. Et tout ce que nous allons faire, c'est que nous allons juste attendre notre sommeil de point d'E/S asynchrone pour cette durée. Et cela, nous pouvons réellement faire une méthode statique puisque nous n'utilisons aucun de nos attributs de classe ici. Donc, nous avons aussi besoin de notre méthode de course. Donc, nous allons définir juste la manière normale. Et dans notre méthode d'exécution, ils sont ici, nous voulons commencer à consommer réellement notre boucle d'événements. Nous allons donc aller de l'avant dans l'exécution de points d'E/S asynchrones. Et maintenant, nous devons fournir le point d'entrée principal pour notre boucle événementielle, ce que nous voulions faire. Nous avions aussi besoin de trouver cette routine au sein de notre classe. Donc on va aller dans le def asynchrone. Et puis on va juste, Hey, j'ai là, on appellera ce sommeil consécutif. Et ce que nous allons faire ici, c'est que nous allons avoir une liste de tâches que nous allons d'abord planifier et ensuite nous allons juste les attendre. Donc nous allons aller de l'avant et bien, nous pouvons avoir notre attente, qui va être notre plateau à nouveau. Et puis nous dirons pour la durée, en durées à notre attente. Nous allons ajouter et ensuite nous allons créer une tâche. Nous allons donc créer une tâche en utilisant l'async self.age, dormir pour cette durée. Donc, fondamentalement, ce que nous avons fait aussi dans la dernière leçon, nous avons notre ensemble en attente. Ensuite, nous allons planifier un tas de tâches en fonction des durées d'entrée ici. Et nous allons avoir que tous gardent une trace de tout ce qu'il y a là en attente. Et puis nous allons dire, alors que la durée du brevet est supérieure à 0. Et puis nous allons dire que c'est fait et offensant égal au poids du point d'E/S asynchrone. Et nous allons attendre sur nos tâches planifiées. Et nous allons utiliser un délai d'attente de seulement 1 seconde ici. Et nous dirons quatre, fait la tâche et fait. Nous allons imprimer
la réponse que nous avons et la tâche qui n'est actuellement rien. Allons donc juste ici et retournons juste la durée juste pour que nous retournons quelque chose. D' accord, et ensuite nous allons appeler ça dans notre méthode d'entrée pour la classe multitraitement. Donc, ici, nous allons exécuter notre code, sel-dot slips consécutifs. Ok, alors reprenons
ça une fois de plus en termes de ce qu'on fait ici. Nous héritons de la classe de processus multitraitement point. Et cela signifie que lorsque nous lançons cette classe, nous lançons essentiellement un enfant qui hérite de ce processus. Donc, nous pouvons créer un nouveau processus pour cela qui peut fonctionner sur un noyau séparé nous CPU séparé. Nous allons également lui fournir un ensemble de durées. Encore une fois, c'est juste d'avoir quelque chose ici pour
que certaines tâches se connectent à être effectuées pour nous. Maintenant notre point d'entrée, et vous vous souviendrez de cela à partir du filetage. Nous n'avons pas abordé trop de détails pour cela, pour le multitraitement, mais vous vous souviendrez de cela à partir du thread. C' est chaque fois que nous appelons les points start, C'est là que nous allons exécuter cette méthode de course ici. Et dans notre méthode d'exécution, tout ce que nous faisons, c'est que nous fournissons le point d'entrée pour notre processus asynchrone. Donc, nous allons appeler async IO dot run. Et ici, nous allons juste avoir la co-routine principale, qui va être ce sommeil consécutif, que nous avons défini ici. Et maintenant cela, vous reconnaîtrez probablement de la leçon précédente où nous ajoutons simplement en planifiant un ensemble de tâches. Et chacune de ces tâches va juste dormir pendant une certaine durée. Et alors que nous avons encore des tâches en attente, nous allons simplement utiliser cette méthode d'attente d'E/S asynchrone. utilisant nos tâches en attente ici avec un délai d'attente de 1 seconde et chaque seconde que nous allons parcourir sont tâches
effectuées et nous allons imprimer les résultats en utilisant cet appel d'attente ici. Donc maintenant, la chose cool avec ceci est que nous pouvons créer plusieurs processus. Et ils peuvent alors, nous pouvons ensuite diviser le travail comme ça. Et nous pouvons en fait avoir plusieurs boucles d'événements en cours d'exécution. Un sera sur chaque processus. Donc, créons les durées initiales, que nous pouvons juste initialiser pour être vides. Et puis nous dirons pour moi dans la gamme de 1 à 11, tout comme nous l'avons fait pour deux durées, nous allons ajouter I. Et maintenant nous pouvons aussi créer deux processus si nous le voulons. Donc, nous allons juste avoir notre liste ici des processus. Et nous allons dire pour moi dans la plage 2, et je ne vais pas faire trop de choses ici. Je vais ajouter à notre processus et à version
initialisée de notre as et classe multitraitement ici. Et nous allons l'initialiser avec quelques durées. Et ce seront des durées. Et puis on va passer de I à, donc tu dois faire I fois 5, jusqu'à I plus une fois 5. Et ainsi de suite. De cette façon, nous allons passer en gros par incréments de cinq. Donc quand j'aurai 0, on passera de 0 à 5. Ce sera donc les cinq premiers éléments. Et quand j'en ai un et qu'on passera de cinq à dix. Donc, fondamentalement, la technologie prend les cinq autres éléments à partir de là. Et maintenant, nous avons nos deux processus, mais nous devons quand même les commencer. Donc, nous allons dire pour P et les processus, nous allons juste appeler p dot start à la toute fin pour p et les processus, nous allons appeler P dot join. Donc nous attendons que ça finisse. D' accord, alors allons-y et lançons ça. Et il semble que j'ai une erreur de syntaxe ici. Laisse-moi aller de l'avant et jeter un oeil à ce qui se passe ici. Et allons de l'avant et faisons défiler nos journaux. Donc notre Coubertin n'a jamais été pondérée. Essayons encore une fois. On y va. Donc maintenant, nous sommes essentiellement en cours d'exécution sur deux processus distincts. Et oui, on est capable de faire ça gentiment. L' un d'eux est la planification d'un ensemble de tâches ici, ils veulent une planification de l'autre ensemble de tâches. Évidemment, ce n'est pas super optimal parce que, pour un, nous ne dormons que pendant dix secondes et nous avons beaucoup de la tâche plus courte sur un processus et beaucoup de plus long test mis un autre. Donc, un processus va vraiment se terminer. Donc, nous pouvons aussi imprimer ici. processus terminé sur les processus va se terminer avant l'autre, ce qui signifie qu'il y a un certain temps où l'un de nos deux processeurs dans ce cas que nous utilisons ou chaque fois que deux cœurs que nous utilisons sont restés inactifs tandis que l'autre est toujours en cours d'exécution. De toute évidence, nous pouvons
mieux répartir cette charge de travail pour en tirer un meilleur effet. Mais c'est quand même, ça marche bien. Donc, maintenant, nous sommes en mesure de combiner un multitraitement ainsi que asynchrone ensemble et avons pu contourner certaines des limitations que nous aurions avec un seul thread et être en mesure d'exécuter une seule boucle d'événement. Et essentiellement faire le plus usage d'un matériel si nous avons plus d'un cœur, en étant en mesure de faire usage du multitraitement. Et grâce à cela, être en mesure d'avoir une boucle d'événement individuelle s'exécutant sur chaque processus individuel, ce qui peut, espérons-le, nous aider à accélérer encore plus les choses. Parce que nous pouvons entrer dans ces limites où nous allons toujours passer beaucoup de temps à attendre juste parce que, vous savez, quelles que soient les raisons pour lesquelles, vous savez, les
choses sont lentes et nous pouvons toujours, même si nous avons co-routines, si nous avons des milliers de co routines sont soudainement avec des tâches planifiées, nous ne pouvons quand même passer d'une d'entre elles à la fois. Donc, si nous avons plus d'une boucle d'événement, nous sommes sur plus d'un processus, nous pouvons réellement passer plus de travail plus rapidement. Et quand les tâches sont faites, nous pouvons les atteindre plus rapidement ou quand ils sont terminés, Ils sont processus d'attente. Nous pouvons les contacter plus rapidement afin qu'ils puissent continuer leur travail plus rapidement ou passer les choses en aval et devenir vraiment compliquées. Aussi comme nous l'avons fait dans notre exemple de thread. Mais le passer au niveau supérieur parce que maintenant nous combinons ce comportement asynchrone dans lequel nous pouvons obtenir cette concurrence, ainsi que le multitraitement, ce qui nous donne une concurrence supplémentaire avec un calcul supplémentaire. Nous sommes donc en mesure de gérer à la
fois les délais d'attente réseau avec le processus asynchrone ou simplement les E/S générales, pas même le timeout pour être juste des temps d'attente d'E/S généraux. Et nous pouvons tirer le meilleur parti de notre matériel en utilisant le multitraitement afin que nous puissions utiliser toutes les ressources dont nous disposons et en tirer le meilleur parti. Maintenant, une dernière chose que je veux mentionner, qui est quelque chose que nous n'avons pas rencontré ici et peut même ne pas être quelque chose que vous avez jamais à traiter, mais juste être conscient parfois que les tâches peuvent aussi expirer. Donc, si vous planifiez trop de choses et que vous avez un paramètre de timeout là-dedans. Il se peut que vos tâches s'écoulent avant même que vous puissiez les atteindre. Donc méfiez-vous de ça si vous commencez à rencontrer des problèmes extrêmement bizarres parce que vous avez construit ce programme extrêmement complexe qui fait juste beaucoup de travail, alors c'est peut-être quelque chose que vous voulez surveiller est, vous savez, J' ai mon planning trop de tâches en même temps et ou certains d'entre eux effectivement en dehors avant que je puisse même arriver à traiter avec eux. Dans ce cas, vous voudrez peut-être réduire la taille de vos lots afin que vous puissiez les traiter de manière plus efficace. Donc juste un dernier conseil qu'ils sont si vous voulez aller vraiment au fond avec ça et essayer de construire quelque chose de très grand et complexe qui va prendre soin de beaucoup de choses. Il suffit d'être conscient de la taille de vos lots. Parce que, tu sais, ça pourrait ne pas être quelque chose, mais ça pourrait être quelque chose que tu pourrais rencontrer. Et je peux causer beaucoup de maux de tête si tu n'es même pas sûr de ce que tu cherches. Mais oui, donc j'espère que vous avez apprécié ça et j'espère que vous avez beaucoup appris et j'espère que vous pouvez construire des programmes simultanés et parallèles vraiment cool maintenant.