Gleichzeitige Programmierung in Python | Max S | Skillshare

Playback-Geschwindigkeit


  • 0.5x
  • 1x (normal)
  • 1.25x
  • 1.5x
  • 2x

Gleichzeitige Programmierung in Python

teacher avatar Max S, Power through programming

Assista a este curso e milhares de outros

Tenha acesso ilimitado a todos os cursos
Oferecidos por líderes do setor e profissionais do mercado
Os temas incluem ilustração, design, fotografia e muito mais

Assista a este curso e milhares de outros

Tenha acesso ilimitado a todos os cursos
Oferecidos por líderes do setor e profissionais do mercado
Os temas incluem ilustração, design, fotografia e muito mais

Aulas neste curso

29 aulas (6 Std. 9 Min.)
    • 1. Gleichzeitige Programmierung Intro

      0:46
    • 2. Threading, Multiprocessing, Async Intro

      13:52
    • 3. Gewindegang in Python

      18:52
    • 4. Erstellen einer Threading

      14:58
    • 5. Einen Wikipedia erstellt

      14:05
    • 6. Erstellen eines Yahoo Finance Readers

      16:23
    • 7. Warteschlangen und Masterplaner

      15:06
    • 8. Einen Postgres Worker erstellen

      21:54
    • 9. Integration des Postgres Workers

      20:11
    • 10. Yaml Intro

      18:30
    • 11. Erstellen eines Yaml

      30:54
    • 12. Unseren Wiki verbessern

      28:21
    • 13. Alle Arbeiter verbessern und Überwachung hinzufügen

      29:01
    • 14. Endprogramm bereinigung

      7:13
    • 15. Verriegeln

      12:06
    • 16. Multiprocessing Intro

      7:27
    • 17. Multiprocessing Warteschlangen

      7:35
    • 18. Multiprocessing Pool

      10:40
    • 19. Multiprocessing Pool Mehrere Argumente

      4:05
    • 20. Multiprocessing Mehrere unterschiedliche Argumente

      4:45
    • 21. Multiprocessing Checking Elemente In Der Liste In Bestimmten Bereichen

      6:28
    • 22. Einführung in das Schreiben von asynchronen Programmen

      12:10
    • 23. Asynchrone Aufgaben

      6:30
    • 24. Async

      7:39
    • 25. Async verwenden

      3:12
    • 26. Asynchroner für Schleifen erstellen

      3:00
    • 27. Asynchroner Bibliotheken

      10:28
    • 28. Die Async

      10:06
    • 29. Async und Multiprocessing kombinieren

      12:14
  • --
  • Anfänger-Niveau
  • Fortgeschrittenes Niveau
  • Fortgeschrittenes Niveau
  • Alle Niveaus

Von der Community generiert

Das Niveau wird anhand der mehrheitlichen Meinung der Teilnehmer:innen bestimmt, die diesen Kurs bewertet haben. Bis das Feedback von mindestens 5 Teilnehmer:innen eingegangen ist, wird die Empfehlung der Kursleiter:innen angezeigt.

126

Teilnehmer:innen

--

Projekte

Sobre este curso

In diesem Kurs lernst du, wie du in Python multi-threaded erstellt hast, damit deine Programme noch schneller laufen können.

Wir gehen in eine Einführung vor, wo mögliche speed herkommen und wie wir diese Probleme lösen könnten, und dann tauchen wir direkt in die technischen Inhalte ein und erstellen ein multi-threaded das Daten aus dem Internet erfasst, Parsen und in einer lokalen Datenbank speichert.

Den lecture findest du in diesem GitHub-Repository .

Triff deine:n Kursleiter:in

Teacher Profile Image

Max S

Power through programming

Kursleiter:in

Nota do curso

As expectativas foram atingidas?
    Superou!
  • 0%
  • Sim
  • 0%
  • Um pouco
  • 0%
  • Não
  • 0%

Por que fazer parte da Skillshare?

Faça cursos premiados Skillshare Original

Cada curso possui cursos curtas e projetos práticos

Sua assinatura apoia os professores da Skillshare

Aprenda em qualquer lugar

Faça cursos em qualquer lugar com o aplicativo da Skillshare. Assista no avião, no metrô ou em qualquer lugar que funcione melhor para você, por streaming ou download.

Transcrições

1. Introdução de programação simultânea: Olá e bem-vindo. Meu nome é Max, fundador da codificação com Max e ponto de verificação de dados. E neste curso, vamos passar por programação simultânea e paralela em Python. Vamos aprender sobre como podemos escrever programas de threading, como podemos escrever programas de multiprocessamento, bem como como como também podemos escrever aplicativos assíncronos. E nós vamos passar, e nós estamos realmente indo para construir um programa muito grande encadeado que vai ler dados do Yahoo Finance para obter um processo e, em seguida, carregado em bancos de dados. E então nós também vamos escrever programas de multiprocessamento para que possamos ter certeza de que podemos fazer o melhor uso de todos os núcleos de CPU disponíveis em sua máquina. E então também vamos aprender sobre como podemos escrever aplicativos assíncronos, como eles funcionam e para que você pode usá-los. Então, com isso, espero vê-lo lá dentro. 2. Rosando, multiprocessing e a introdução em Async: Olá, é o Max e bem-vindo. Neste módulo vamos aprender sobre programação simultânea. Agora, antes de entrarmos e escrevermos alguns programas legais, vamos rapidamente obter um esboço e uma visão geral do que vamos abordar aqui para que estejamos todos preparados e entendamos geralmente o que vamos fazer. Então, primeiro de tudo, o esboço desta lição é que primeiro vamos ter uma breve introdução à simultaneidade, apenas olhando para alguns exemplos e por que é ainda legal e por que podemos querer usá-la. E então vamos entrar em algumas considerações de coisas que temos que ter em mente quando pensamos em escrever programas simultâneos. Tudo bem? Normalmente, quando estamos escrevendo programas, é muito provável que estejamos escrevendo programas sequenciais. Então uma coisa acontece depois da outra. E na maioria das vezes estamos basicamente quase todo o tempo até agora está escrito apenas usando uma única CPU. Então isso significa que não estamos realmente fazendo pleno uso de todos os recursos que podem estar disponíveis para nós. Então vamos dar uma olhada neste exemplo aqui. Digamos que nossa máquina tem quatro núcleos e estamos executando um programa Python. E basicamente o que estamos fazendo é calcular várias métricas. Temos um arquivo de fonte de dados de algum lugar, e nós só queríamos calcular algumas métricas diferentes. Então a maneira que podemos fazer este programa executar é primeiro calculamos a primeira métrica, então calculamos a segunda, então calculamos a terceira, e então salvamos tudo em um arquivo. E se tivermos quatro núcleos, isso significa que um dos nossos núcleos é, vai estar executando este programa e os outros vão ficar ociosos. Agora, é claro, há outras considerações. Sabe, se estamos rodando isso em nossa máquina pessoal porque podemos ter outros aplicativos abertos, etc., etc. Mas se estivéssemos em um ambiente de nuvem ou algo assim e realmente tivermos mais recursos de CPU disponíveis, então pode ser que não estejamos fazendo uso total de todos esses recursos disponíveis. Então poderia ser feito em vez disso é que poderíamos ter um programa que calcula jogo métrico. E eu meio que mudei os tamanhos aqui para mostrar que as diferentes métricas podem levar uma quantidade diferente de tempo para calcular. Então você tem métrica a, que vai ser executado no primeiro núcleo. E temos a métrica B, que será calculada ao mesmo tempo no segundo núcleo. E então temos SI métrico, que vai ser calculado ao mesmo tempo no terceiro núcleo. Então, como essas métricas são independentes umas das outras, podemos calculá-las todas ao mesmo tempo. Não há razão para esperarmos que um termine. E depois fazemos o segundo, e depois fazemos o terceiro. Poderíamos calculá-los todos ao mesmo tempo. E então, uma vez que cada um deles é terminado, nós também poderíamos apenas escrevê-los em um arquivo. E então, se quiséssemos, poderíamos mesclar todos os arquivos juntos ou algo que também podemos fazer é simplesmente substituir salvar em um arquivo em vez de escrever em um banco de dados. Então isso será calcular uma métrica e então escrevemos no banco de dados e então, você sabe, essa parte está feita. Então, neste caso, o que temos aqui é que temos um programa mais intensivo de CPU. Há muitos cálculos acontecendo, no gargalo são realmente os cálculos. E assim, neste caso, é bom fazer uso de nossos diferentes núcleos são diferentes recursos de computação para que possamos fazer mais cálculos ao mesmo tempo. Mas há também outros programas que podemos escrever onde não é tanto cálculo, mas na verdade um monte de tempo gasto pelo programa é apenas esperando por respostas de rede. Então, por exemplo, algo que poderíamos fazer é pedir, eu sou de algum lugar. Isso pode ser uma API. Isso pode ser de um raspador de teia, pontos, você sabe, bater no site. Mas de qualquer forma, estamos apenas solicitando dados de algum lugar. E depois estamos à espera que a resposta volte para nós. E agora temos os dados disponíveis. E então podemos escrevê-lo em um arquivo, por exemplo, ou podemos escrevê-lo em um banco de dados e correr para um banco na verdade é, então, enviar a solicitação para dizer, ok, por favor escreva isso e, em seguida, aguardando até a resposta da rede. Sim. Ok, está escrito. E então se estamos fazendo isso para vários pedaços de dados e talvez nós, nós, nós pedimos o primeiro pedaço de dados e então nós esperamos a resposta para eles, nós escrevemos e então nós podemos solicitar o segundo pedaço de dados, esperar pela resposta, e, em seguida, escrevê-lo. E a escrita em si tem novamente, enviando a direita e depois esperando que ela seja reconhecida. Então, neste caso, estamos apenas gastando muito tempo esperando que as coisas aconteçam. Estamos gastando muito tempo esperando apenas sinais de reconhecimento. Sim. Aqui estão os seus dados. Ok, finalmente está disponível para nós, como como ser transferido pela rede. Ou aqui vamos nós, sim, Os dados foram agora salvos no banco de dados. Então podemos ter, neste caso, podemos ter vários segmentos. Então, ainda temos tudo em execução em uma única CPU em um único núcleo. Mas temos vários programas simultâneos rodando no mesmo núcleo. Então podemos ter uma linha principal, que basicamente, se não quiser fazer mais nada, pode haver algumas coisas acontecendo de antemão, mas realmente pode começar Oliver Child, Threads infantis. E então o que o primeiro thread filho fará é que ele vai solicitar dados. E enquanto ele está esperando, o segundo tópico pode então solicitar que é theta. E então, quando os dados entram, então ele pode, o primeiro tópico pode dizer, ok, agora eu tenho meus dados e eu vou escrever isso em um banco de dados. E depois passa o tempo à espera outra vez. E enquanto um thread está aguardando comunicação de rede, para confirmações de rede, o outro thread pode estar fazendo seu trabalho. E assim você pode ver aqui. Temos dois segmentos que estão sendo executados simultaneamente, todo o tipo de desligamento. Uma solicitação dos dados e quando ele está ocioso, quando ele está apenas esperando que a rede dê uma resposta a eles, o outro thread pode estar em execução. Agora há outro exemplo de coisas que podem acontecer é que podemos ter um monte de escrever para bancos de dados. Então, uma coisa aqui, é claro, como podemos fazer é usar threads, novamente para ter vários threads, cada um deles direitos para um banco de dados. E enquanto esse thread está aguardando o banco de dados para dar uma confirmação, o outro thread pode iniciar sua direita, et cetera. Agora também podemos usar um programa assíncrono onde você basicamente enviar o direito e, em seguida, você continuar com o programa. E sempre que você recebe o reconhecimento, então você meio que volta para a parte concluída e segue em frente com o programa. Portanto, seu programa não está bloqueado por esses tempos de comunicação de E/S de rede, mas em vez disso você apenas escreve no banco de dados. Como você pode ver no lado direito aqui. Então escrevemos para o banco de dados, e enquanto esperamos pela confirmação, iniciamos a segunda direita para talvez um banco de dados diferente e então podemos até escrever talvez para um terceiro banco de dados. E então tudo isso está acontecendo e em segundo plano, você sabe, estamos esperando até ouvir um reconhecimento de qualquer um dos bancos de dados que nós realmente escrevemos. E sempre que tivermos esse reconhecimento, podemos continuar com essa parte do programa. E isso realmente nos ajuda a economizar muito tempo que, de outra forma, passaríamos apenas sentados ociosos esperando que a comunicação de rede acontecesse. Agora isso pode não parecer grande coisa porque, você sabe, a velocidade da internet pode ser muito rápida. Mas se você estiver fazendo muita comunicação de rede como se estivesse escrevendo um monte de valores. Então, se você está enviando um monte de solicitações, seu programa pode estar gastando muito tempo apenas sentado ocioso, esperando. E assim, ter essa opção de usar threads para fazer coisas enquanto estamos esperando ou sendo capazes de fazer uso de vários núcleos de CPU se tivermos operações de computação intensiva, isso pode realmente ser um grande benefício para nós e pode acelerar nossos programas dramaticamente. Agora, há, é claro, algumas desvantagens e considerações que precisamos fazer aqui. Então a primeira coisa que precisamos estar cientes como Python tem algo conhecido como bloqueio de intérprete global, que basicamente significa que só podemos estar executando um thread de cada vez. Então você pode ver aqui se voltarmos para o exemplo, se olharmos para filho um e filho thread para thread filho selvagem, um está iniciando a solicitação para os dados. O capítulo 2 está realmente ocioso. Não está iniciando seu próprio pedido. É só o relógio. O alvo um está inativo onde está esperando. Esse thread filho T2, por exemplo, pode começar a trabalhar. Então eles não são exatamente simultâneos, mas os fios estão tipo de revezamento. E sempre que um está ocioso, outro pode tipo de pular e levar esse tempo de CPU. Então, sempre que algo está ocioso, é quando eles podem entrar. Então não é uma simultaneidade perfeita, mas é claro que ainda temos acelerações dramáticas porque não temos que gastar todo esse tempo esperando e enquanto esperamos, não estamos fazendo mais nada. Agora há também uma questão importante. Temos que pensar que nem tudo pode ser seguro. Então basicamente seria thread-safe significa que é ok para vários threads para estar lidando com uma determinada entidade. Ou nossos tópicos estão lidando com dados de uma forma que não interfira com outras ameaças. Agora, uma maneira de seguirmos a segurança da rosca é usando o bloqueio. De outras maneiras também apenas escrever programas seguros de thread que não levam a coisas estranhas acontecendo quando vários threads estão tentando acessar, por exemplo, compartilhar um pedaço de dados. Então, uma dessas coisas que podemos obter se não tivermos segurança na linha é algo chamado condição de corrida. Agora isso é algo que você verá aqui em threads, mas também pode surgir quando você sabe que está aprendendo sobre bancos de dados. Mas basicamente uma condição de corrida é quando dois programas separados ou entidades ou threads, neste caso, tentam acessar e modificar o mesmo pedaço de dados ou até mesmo usar os mesmos dados. Então, por exemplo, vamos dizer que temos dois threads que ambos fazem uso de uma variável a. E thread um lê a variável e, em seguida, modifica-lo e, ao mesmo tempo, ou pouco antes ou pouco depois thread para também ler para a variável e em seguida, escreve para ele. E há muitas coisas diferentes que podem acontecer. Então, por exemplo, digamos que cada um desses threads apenas incrementando a variável. Se nossos dois tópicos os lerem quase simultaneamente, então ambos verão o mesmo valor. E então um segmento, um tipo de coloca o resultado n e apenas incrementa por um. Thread 2 não terá visto esse novo valor, mas teria visto o valor anterior. E assim, quando ele incrementa por um, é apenas no total vai ser incrementado por um em vez de dois porque ambos lêem em um momento semelhante antes de um dos outros terminar sua operação. E então, é claro, você pode ter outras variações de basicamente o mesmo problema. Onde você substitui a variável, você executa alguma operação downstream, por exemplo, adição ou multiplicação e, em seguida, você não usá-la mais tarde. Mas como os tópicos estão acontecendo ao mesmo tempo, é muito difícil para nós saber exatamente. É basicamente impossível para nós saber qual segmento vai estar acessando no início, especialmente tipo de saber isso sobre diferentes execuções do mesmo programa. Então, se executarmos novamente o nosso programa, isso pode levar a resultados imprevisíveis porque às vezes um segmento o torna o primeiro e, às vezes, outro segmento pode chegar lá primeiro. E às vezes podemos ter uma condição de raça. Às vezes podemos não, porque eles também são fatores externos em jogo. E assim. As condições de corrida podem levar a resultados muito imprevisíveis. E assim ter isso em mente é muito importante que se você tiver dados compartilhados ou algo assim, você sempre precisa pensar sobre isso. Segurança do fio é o programa que estou escrevendo pode interferir com ele mesmo. E se você estiver usando outros módulos ou bibliotecas em Python, e alguns deles dirão especificamente essa entidade, por exemplo, essa classe que você está usando é thread-safe ou essa classe não é thread-safe. E então você precisa estar ciente e cuidadoso com eles porque isso pode levar a bugs muito, muito estranhos, complicados e confusos que são difíceis de reproduzir e muito difíceis de rastrear. Então, a outra coisa a considerar é antes de tudo falar sobre fio. Especificamente, os threads são executados em um único núcleo de CPU e todos eles compartilham a mesma memória, é por isso que temos essa questão de segurança de threads e condições de corrida. E há também uma pequena sobrecarga associada com apenas thread switching entre os diferentes threads, bem como apenas o gerenciamento dos threads na auto-criação, derrubando os threads. Considerando que para o multiprocessamento eo que temos é que temos diferente o mesmo programa rodando em diferentes núcleos de CPU, ou a mesma parte deste programa rodando em diferentes núcleos de CPU. E então, na verdade, neste caso, nós não temos uma memória compartilhada. Cada processo tem seu próprio interpretador Python e seu próprio bloqueio de intérprete global. Então, é claro, isso é ótimo porque não precisamos ter alguns desses problemas que temos com ameaças, por exemplo. Mas também há mais memória. Há também mais sobrecarga associada a isso. Então, um deles é reduzir muito do uso de memória. E há muito mais memória que precisa ser usada para criar e replicar todos esses processos diferentes entre os diferentes intérpretes. E apenas sobre simultaneidade em geral, é muito legal e pode ser extremamente útil rapidamente. Nós também queremos ter certeza de que os programas que você está escrevendo vão realmente valer a pena escrever e uma maneira simultânea. Porque escrever e depurar programas simultâneos pode ficar muito complexo e às vezes torna-se difícil encontrar problemas em sua lógica ou depurar determinados problemas por causa de toda essa simultaneidade acontecendo. Então, sim, considerando simultaneidade, podemos definitivamente obter speedups incríveis. Mas lembre-se também que nem todos os programas têm que ser simultâneos. E está tudo bem, você sabe, continuar escrevendo um monte de programas sequenciais. Mas então você vai notar como, oh meu Deus, eu estou gastando tanto tempo esperando por tudo isso não funcionar. Eu, eu realmente posso fazer uso de multithreading aqui, ou não há nenhuma razão para eu calcular essas 80 métricas sequencialmente. Eu vou apenas usar o multiprocessamento e fazer uso de quatro ou dois ou oito ou pairar muitos núcleos que você tem disponível em sua máquina ou no ambiente de nuvem e apenas indo para acelerar o processo. Então eles estão definitivamente escrever situações para usá-lo. Mas também há, você sabe, nós não temos que escrever todos os programas simultaneamente. Então, basta ter isso em mente porque a simultaneidade adiciona complexidade à escrita e à lógica e também à depuração. 3. Rosqueamento em Python: Tudo bem, então vamos em frente e realmente escrever nosso primeiro programa simultâneo. Vamos começar com rosqueamento. Agora eu vou estar usando PyCharm para isso, mas você pode, claro, ir em frente e sinta-se livre para usar qualquer que seja o seu ambiente de codificação favorito. Eu gosto muito de usar PyCharm quando temos vários arquivos, que eu realmente vou acabar, você sabe, indo para a parte posterior de como estamos progredindo através do threading. Então, sim, bem como trabalhar com gráfico de pizza para isso. Caso contrário, você sabe, se eu estiver fazendo um teste rápido e prototipagem e eu preciso manipular ou tipo de querer olhar para trás em muitos dados que foram criados ao longo de um programa ou apenas tipo de brincar com as coisas. Para isso, eu geralmente gosto de usar uma aranha ou Jupyter Notebooks. Mas além disso, eu gosto muito de usar PyCharm. Novamente, isso é completamente com você. Então acabei de criar uma pasta na minha área de trabalho aqui onde vamos salvar todo o nosso trabalho. Vou criar um novo arquivo e chamar esta caixa. Eu só vou chamar isso de meu principal, mas você pode chamá-lo do que quiser, desde que ele tenha a extensão dot py. E eu vou estar fazendo algo aqui que você provavelmente verá muito em programas Python. E vamos começar definindo uma função principal. E vamos passar por aqui, o que nos permite basicamente dizer que voltaremos a isso mais tarde. Por isso, neste momento, não vai fazer nada. Vamos ter a sintaxe aqui. Se sublinhado, sublinhado, nome, sublinhado, sublinhado for igual a. E então temos sublinhado. Sublinha, sublinhado, sublinhado, sublinhado principal, sublinhado. E então vamos executar a função principal. Agora, basicamente, o que esta sintaxe significa é que se este programa é executado diretamente, não quando é importado ou qualquer coisa, apenas um este programa é executado especificamente. É quando isso será executado. Caso contrário, se importarmos isso, então ele não será executado. Então isso é apenas uma sintaxe de olhos coordenados. Eu gosto muito disso. E você provavelmente verá isso em muitos programas Python. Claro, não é completamente necessário, mas é bom se você quiser testar o código que você está escrevendo aqui quando ele meio que quer executá-lo. Mas caso contrário, se você quiser importá-lo, você não quer que ele seja executado. Certo, então temos nossa principal função aqui. E basicamente o que vamos fazer é escrever, bem, duas funções. A primeira função vai calcular a soma dos quadrados. Então vamos chamá-lo de def, calcular quadrados de soma e ele vai ter uma entrada. Podemos dizer “n” por enquanto. Vamos definir isso em um segundo. E a nossa segunda função vai dormir um pouco. E então nós vamos apenas fornecer, e aqui a entrada e segundos por quanto tempo nós gostaríamos que ele dormisse. E vamos definir isso em um segundo também, porque primeiro precisamos importar o módulo de tempo, que nos permitirá fazer isso dormindo. Então eu quero dizer funcional modificar isso em um segundo. Então, para dormir um pouco, tudo o que vamos fazer aqui é chamar a função do sono. E vamos dormir por tantos segundos. Para calcular a soma dos quadrados, vamos apenas ter uma variável de soma quadrados que vamos iniciar para 0. Vamos ter um loop for para mim ao alcance. E, e em cada iteração nós vamos ter nossa soma de quadrados adicionar neste número ao quadrado. E então, no final, vamos apenas imprimir a soma dos quadrados aqui. Ok? Então, agora em nossa função principal, Vamos em frente e ter 24 loops. Eu vou dizer para eu no intervalo cinco, nós vamos apenas executar o cálculo da soma dos quadrados. E esta vai ser a nossa entrada aqui. E nós vamos ter uma segunda função que vai dizer para eu no alcance, começando de um, indo para o sexo. Então nós dormimos a primeira iteração, vamos chamar de sono um pouco. E vamos ter o nosso valor, ouvi dizer. E também teremos temporizadores que queremos configurar. Então vamos medir os tempos de cálculo do nosso programa. E também podemos usar o módulo de tempo para isso. Então vamos ter o nosso horário de início de cálculo vai ser definido como o carimbo de data/hora atual neste momento. E então uma vez que isso é feito, vamos dizer calcular a soma dos quadrados tomou. E então vamos tomar o tempo no momento atual menos o carimbo de data/hora que temos neste momento. E nós primeiro salvamos nossa variável aqui. Agora, isso vai nos dar uma saída com um monte de números decimais. Então o que vamos fazer em vez disso é usar o método redondo, e vamos arredondá-lo para uma casa decimal, lugar para obter este tipo de redução um pouco, um pouco mais limpo. E então o que vamos fazer para dormir, vamos fazer uma coisa semelhante. Vamos dormir, comece. Tempo, que também vai ser apenas o rastreamento, o tempo neste momento, salvando-os para uma variável. E então novamente aqui vamos estar dormindo. Levou a hora atual menos a hora de início. Foi o tempo que demorou. E para realmente ter os cálculos levar algum tempo. Nós não vamos apenas colocar no seu olho, mas vamos em frente e fazer isso ser I plus 1, em primeiro lugar. E então nós também vamos multiplicá-lo por 1 milhão, apenas para que ele leve um pouco de tempo. Agora podemos comandar isto. Basta, por exemplo, clicar no botão Executar aqui. E ele vai, bem, começar a executar o programa sequencial para nós. E assim podemos ver aqui atualmente a soma dos quadrados está no trabalho e levou cerca de sete segundos, arredondado para uma casa decimal que podemos ver aqui. E agora o nosso programa vai dormir iterativamente. Então, 1 segundo, 2 segundos, 3 segundos, 4 segundos, 5 segundos. E então, no final, vamos ver, ok, então todo o processo levou 15 segundos. Então, no total, nosso programa levou cerca de 21 segundos ou 22 segundos. Você tem 15 aqui mais 7. Então, sete deles eram para o cálculo e 15 deles para o sono. Certo, então este é um programa sequencial. Então vamos em frente e tentar adicionar alguma simultaneidade aqui. Vamos usar roscas para isso. Então vamos importar rosqueamento. Agora, a coisa boa é, threading é na verdade parte da instalação padrão do Python. Então você realmente não tem que pip instalar qualquer outra coisa. Você pode simplesmente importá-lo diretamente. Agora, para cada um desses loops aqui, vamos agora substituir isso por um segmento. Então nós vamos fazer em cada um desses casos, é que nós vamos criar um thread e vamos chamá-lo t, é apenas vai ser nossa variável curta para thread, thread ponto ameaçador e outras várias variáveis que precisamos definir aqui. A primeira coisa é o alvo, que vai ser a função que precisa ser executada. E para isso, para este caso, será calcular a soma dos quadrados. Note que não vou colocar os parênteses no final. É apenas o nome da função porque não queremos chamá-la ainda. Esta é uma espécie de referência para a função. Em seguida, também podemos fornecer os argumentos para a nossa função. Temos uma palavra-chave separada aqui, args, e isso espera uma tupla. Então, uma vez que temos apenas um argumento de entrada, vamos ter o nosso valor de entrada aqui. E então nós vamos para o. Vamos ter o nosso, vamos definir o nosso valor máximo vai ser este aqui, apenas para tê-lo e não ser um pouco mais curto. E assim nossa tupla de entrada vai ser isso, mas diz que tem que ser uma tupla. Temos que colocar uma vírgula extra aqui para ter certeza que é uma tupla de tamanho 1. Então vamos comentar isso. E então vamos fazer a mesma coisa aqui. Vamos criar um segmento. E vamos tê-lo como alvo a função de dormir um pouco. E o argumento de entrada que vão fornecer é este olho aqui. E vamos mudar o nome para segundos. Não precisamos saber se esses nomes são os mesmos. Não precisamos de ter isto. Isso só faz um pouco mais agradável de ler. Então eu vou renomear isso para segundos novamente, fazer isso uma tupla. E vamos comentar isso. Agora, se fizermos isso, vai ficar um pouco surpreso porque na verdade nada vai tê-los ainda. E a razão para isso é que realmente precisamos iniciar os tópicos. Então a próxima coisa que temos que fazer é para cada segmento terá que chamar t dot. Comece. Assim. Agora podemos fazer isso e ainda teremos um resultado um pouco estranho. Então vamos em frente e ver isso. Então, repare como nosso programa meio que continuou. E então temos as saídas de impressão. E então isso é aqui. E depois tivemos as somas impressas. Então, obviamente, este não é o tempo que seu programa demorou porque ainda há outras coisas acontecendo. Mas isso é apenas porque os threads estão sendo executados simultaneamente. Então o que queremos é o que queremos que o programa seja bloqueado para esperar até que todos os tópicos terminem. Neste ponto. Isto é quando todos os fios precisam terminar. E então queremos imprimir quanto tempo isso levou. Então, para fazer isso, vamos configurar uma, outra variável. Que seja uma lista. Nós vamos manter o controle de cada um desses tópicos e, em seguida, apenas certifique-se de que nosso programa bloqueia até que eles estejam todos terminados. Então vamos chamar essa variável de ameaças atuais. E novamente, você pode chamá-lo de qualquer forma. E toda vez que criamos um thread, vamos acrescentar aqui o thread para que possamos referenciá-lo mais tarde. Agora vamos passar por cima da nossa lista. E para cada elemento, que é o fio aqui em si, vamos chamar ponto join. Agora, o que a junção de pontos faz é que bloqueia a execução até que este thread é feito. Então nós estamos iterando sobre isso e nós estamos basicamente chamando ponto join, que significa que nada é permitido acontecer até que o thread termine. Então, não pode ir mais longe do que isso, basicamente. Então fizemos isso por aqui. Agora vamos em frente e fazer a mesma coisa aqui. Então vamos reutilizar essa variável e reutilizar isso. Deixe-me colocar isso aqui. E, novamente, vamos chamar dot join para ter certeza de que nosso programa está bloqueado. E depois esperamos que isto termine até executarmos isto. Então, se formos em frente e executarmos isso agora, podemos ver agora, tudo bem, então nossa execução está indo como esperado. E aqui agora temos o nosso sono, ok, então algo interessante de notar. Primeiro de tudo, ouça este um pouco mais rápido, mas, você sabe, realmente nada para se empolgar. E realmente isso é só porque isso é, este é um método intensivo de computação. E assim, na maioria das vezes, você realmente não vai ter quaisquer melhorias de desempenho em termos de como apenas coisas de computação aqui. Então realmente nada que seja fascinante aqui. E se quisermos acelerar as melhorias nesta seção, então vamos precisar ir para o multiprocessamento, já que podemos usar núcleos diferentes. Mas aqui porque cada tipo de thread só pode ser executado ao mesmo tempo e isso é intensivo de CPU, realmente todos esses cálculos, não há muita E/S acontecendo. Então, sabe, basicamente acontece sequencialmente de qualquer maneira. Mas o legal está aqui, e o sono é que a doença é um exemplo muito, muito simples. A suspensão acontece em um nível de thread, modo que um thread diferente pode ser executado enquanto cada um desses threads está ocioso. Então, ao invés de tomar um tempo total de 15 segundos, que é o que nosso programa sequencial tomou. Leva apenas cinco segundos, que é basicamente o sono mais longo que tivemos. O máximo aqui é cinco. Assim, podemos ver neste caso, é claro, este é o exemplo muito, muito básico. Seremos muito mais úteis para não dormir ou programar. Mas em vez disso, você sabe, se isso é algum tipo de conexão de rede, como fazer uma solicitação de API, escrever para um banco de dados de obter de um banco de dados ou, você sabe, qualquer outra coisa, qualquer coisa pesada na rede IO que apenas gasta onde nossos threads estão, onde nosso programa passa muito tempo sendo ocioso, apenas esperando por comunicação de rede e talvez o servidor do outro lado meio fazer a sua coisa e, em seguida, enviar de volta a resposta. Agora nós meio que vimos o básico de criar threads aqui para diferentes funções, mas eu queria mostrar algumas outras coisas que eu acho que são interessantes. Então a primeira coisa é o que teria acontecido se, em vez de chamar juntar-se no final aqui, chamássemos isso aqui. Então vamos em frente e chamar t dot junte-se aqui. E vamos em frente e reexecutar isso. Então, o que acontece neste caso? Agora este ainda está chamando a junção no final aqui. Mas, novamente, isso é como uma CPU. A função ou intensivo em aspas, é claro, mas você sabe, CBO focado. Então você pode ver aqui basicamente sete segundos, que é exatamente o que tínhamos antes. Novamente, não esperamos nenhuma mudança aqui. Mas neste caso, o que acontece é que a chamada Junte-se aqui significa realmente que a execução está bloqueada. Não, este loop não continua. A execução é bloqueada até que este thread seja concluído. Então agora estamos voltando aos 15 segundos que tivemos antes. Porque nós não estamos iniciando todos esses threads e deixando-os rodar e, em seguida, bloqueando o programa no final até que todos esses threads sejam feitos. Mas em vez disso, iniciamos uma discussão e bloqueamos toda a execução até que a ameaça termine. Considerando que antes de começarmos todos os threads e, em seguida, bloqueamos a execução até que todos os threads tenham feito. Então você pode ver aqui mesmo apenas uma pequena sintaxe de ter a junção aqui em vez de aqui. Neste caso, um impacto muito grande sobre nós. Agora, há outra coisa que eu queria te mostrar. Se tirarmos as declarações conjuntas, que é o que não tínhamos começado. E se nos lembrarmos, se reexecutarmos isso, nós meio que temos essa coisa estranha onde nós, você sabe, o programa meio que faz a sua coisa, o fio principal aqui. E agora nós realmente obter toda a impressão e na verdade o sono também está acontecendo para esses diferentes tópicos. Então nós temos 10 tópicos diferentes correndo cinco a partir daqui. Bem, na verdade 11 porque este vai ser o nosso principal aqui, o programa principal, nós criamos cinco tópicos extras aqui. Cinco fios extras aqui. E este termina como basicamente, você sabe, fazendo sua coisa, não é bloqueado por isso, faz essas impressões, e então este está correndo. E está imprimindo a soma dos quadrados. E, entretanto, estes cinco fios estão apenas a dormir. Não estamos imprimindo nenhum sentido, então não vemos. Então algo que você também pode acontecer é que você pode adicionar um daemon fly aqui e definir isso para ser verdade. E podemos fazer a mesma coisa aqui. Agora isso se torna interessante quando executamos isso. Porque o que acontece é que percorremos o thread principal e uma vez que o thread principal termina, todo o programa pára. Então o que a bandeira daemon significa aqui é que uma vez que o thread principal é feito, todos Damon sinalizam Autor. E não importa se eles terminam ou não. Se um thread não é um thread daemon, então cada thread precisa terminar. Todos os que não são Damon ameaçam terminar antes que todo o programa possa terminar. Mas os tópicos Damon não precisam terminar para que o programa termine. Uma vez que o thread principal é feito, em seguida, se qualquer thread daemon ou esquerda, isso realmente não importa. Isso não impede que o programa termine. Então isso é uma coisa interessante, você sabe, dependendo da situação que você pode ou até queria ou você não quer. Mas fique ciente de que ter o vôo declaração aqui significa que esses tópicos, se o programa terminar, o programa principal termina. E se algo é um thread daemon, então isso significa que ele não vai terminar, ele vai apenas parar, o programa está feito. Considerando que se tivermos a bandeira de Daymond como falsa, então esses tópicos também precisam terminar até que todo o programa possa terminar, que é exatamente o que tínhamos antes. Por isso, enquanto isto está a correr, deixa-me pôr isto de volta. Agora há, naturalmente, uma coisa interessante que podemos usar com juntas. Se temos juntar-se, novamente, a declaração conjunta significa que o segmento que cada um desses tópicos que estamos chamando a junção precisa terminar antes que possamos continuar neste ponto, porque ele está basicamente bloqueando até que todos esses tópicos sejam feitos. Então, se reexecutarmos isso, apesar de serem os tópicos Damon, porque estamos chamando essas declarações conjuntas que estão bloqueando a execução posterior. Basicamente garantimos que os programas terminem. Então podemos ver que meio que voltar aos resultados anteriores que tivemos. E podemos levar isso ainda mais longe para dizer, em vez de rever os tópicos do Oliver, talvez só bloqueemos até que os três primeiros estejam prontos. E assim o nosso sono aqui. Esperaríamos que fossem três segundos, já que os outros dois são ameaças ao Damon. E assim ele pode tipo de continuar. Mas os três primeiros vão estar dormindo e vão bloquear a execução. Então você pode ver aqui que é exatamente o que temos. Os três primeiros estão bloqueando a execução uma vez que o terceiro thread termina desta seção, que é uma suspensão por três segundos, o contingente do programa continua em, ele termina, e os únicos threads restantes são threads Damon. Então todo o programa está feito. 4. Como criar um curso de rosqueamento: Certo, acabamos de escrever nosso primeiro tipo de programa encadeado. Agora o que vamos fazer é apertar um pouco e vamos realmente transformar isso em aulas. E eu vou mostrar a vocês como podemos realmente usar classes para encadear para. Então, para fazer isso na primeira realmente vai criar um novo diretório. E aqui nós vamos ter nossos diferentes trabalhadores são diferentes tópicos apenas para, você sabe, ter alguma estrutura. E então aqui, esta vai ser a nossa soma ou calcular soma dos quadrados função é basicamente vai ser colocado em uma classe para que possamos reutilizar. Não faz muito sentido para este caso de uso, mas para outros fins mais gerais. Então isso vai ser r ao quadrado, alguns trabalhadores ponto py, apenas no caso de querermos ter vários. E este aqui vamos ter outro que vai ser a sua função de sono. Então vamos ter que ser r, dormir ser marcadores. E eu também vou e, e sublinhado, sublinhado init, sublinhado, sublinhado dot py arquivo, que vai transformar este diretório aqui para mim em um módulo Python que eu possa importar. Então, nem preciso colocar nada aqui, mas isso só vai me permitir importar deste diretório. Tudo bem, então vamos em frente e começar com r ao quadrado. Algum trabalhador. Primeiro vamos importar rosqueamento. E então vamos criar uma classe. Vai ser r trabalhador soma quadrada. E este trabalhador vai herdar da ameaça do ponto de rosca. Então é uma espécie de herdar da classe thread aqui. E então vamos definir a inicialização da classe. E vamos usar essa palavra-chave super. Normalmente, apenas o conclui automaticamente. Então lá vamos nós. E vamos para a inicialização da classe pai, vamos apenas usar o método super. Agora, o super método aqui, nós apenas definimos a classe que os pais têm que nós queremos inicializar. E então chamamos “self “aqui e então chamamos “dot “nele. E basicamente todas as classes pai que esta classe herda serão inicializadas. Portanto, não precisamos realmente inicializar cada classe pai separadamente. Podemos chamar a inicialização completa de todas as classes pais como esta, o que é bastante conveniente. Neste caso, é claro que só temos uma aula, mas, sabe, se tivéssemos vários aqui e só quiséssemos inicializá-los sem mais problemas. Então podemos fazer assim. Tudo bem? E então o que temos aqui é que vamos ter um cálculo da soma dos quadrados. Então vamos assumir isso. E porque é uma aula, temos que nos colocar aqui. E então todo esse método aqui vai fazer é calcular a soma dos quadrados exatamente da maneira que tínhamos antes. Agora, existem duas maneiras diferentes de fazer isso. Uma maneira é que podemos deixar a entrada aqui para que possamos apenas fornecê-lo através deste método classe. Ou a outra maneira que podemos fazer isso é que podemos parte da inicialização da classe. E então podemos definir um atributo da classe. E então não temos uma entrada aqui. E está úmido, basta referenciar o atributo. Neste caso, não importa muito. Pode ser mais limpo usá-lo aqui. Mas em vez de apenas tê-lo assim é na verdade uma espécie de sintaxe que eu gosto bastante. Porque então, você sabe, se você está escrevendo mais um método, eles acabam tendo como muitos parâmetros de entrada. E assim, desta forma, você pode simplesmente inicializar seus valores. Seu QI pode apenas inicializar sua classe para todos os valores e, em seguida, apenas referenciar parâmetros internos em vez de ter que passá-los para todos esses métodos diferentes se chegar a esse ponto. Então nós vamos realmente usar este método. E agora há outra coisa que podemos fazer, que é que podemos fazer estrelas, estrelas quarks. E então o que isso significa é que isso vai ser um mapeamento de pares de valores-chave para argumentos de palavra-chave adicionais que podemos querer passar. Isso pode ser, por exemplo, nome igual a, e, em seguida, qualquer que seja o nome de entrada vai ser. E então nós podemos ter, você sabe, como persona. Eu não sei de onde isso veio, mas, você sabe, você pode ter todos esses outros parâmetros de entrada. E ao invés de definir cada uma das montanhas tipo de deixá-la aberta, podemos realmente ter esta estrela, palavra-chave estrela, argumentos. E talvez existam parâmetros que realmente queremos passar para o encadeamento que queremos definir. E assim podemos apenas passar esses argumentos de palavra-chave mais adiante aqui. E assim, desta forma, é realmente bom porque podemos fornecer todos esses parâmetros de inicialização que podem apenas ser passados para os métodos pai ou também podemos usá-los nós mesmos. Agora, outra coisa, é claro, que temos que fazer é começar nossa linha. Então temos que fazer isso para ter certeza de que ele realmente começa a funcionar. Agora, o interessante é que quando começamos o thread, realmente se você quiser fazer o cálculo, temos que colocá-lo no método run. Então, se temos um método de execução e se chamarmos estrela self.age porque estamos herdando da classe thread. Ele vai iniciar o thread e eu vou apenas começar a executar o método run. E assim podemos sobrescrever o método de execução que herdamos da classe thread para fazer a execução para nós. Então, neste caso, na verdade, o vamos fazer é apenas calcular a soma dos quadrados. Então nós não estamos realmente indo para chamar este método. Nós vamos apenas criar a classe e então ela vai executar a corrida para nós. Certo, então mais uma pequena sintaxe aqui. Eu só vou adicionar um sublinhado porque apenas para indicar que é tipo de um método interno que vamos usar, você sabe, internamente na sala de aula. Tudo bem, então esta vai ser a nossa aula de rosqueamento, 4 ao quadrado, algum marcador. Agora vamos fazer a mesma coisa pelo nosso Yorker adormecido. Então, novamente aqui vamos importar o threading. Nós vamos criar o marcador sonolento classe, que vai herdar da rosca doca de rosca. Vamos inicializar a classe e inicializar a classe pai. E vamos permitir argumentos de palavra-chave que vamos passar para as inicializações das classes pai. E também aqui onde podemos colocar em segundos por quanto tempo? Por quantos segundos queremos que isso durma, o que é, claro, usaremos um segundo. Então aqui vamos dormir. Uma pequena função, que é apenas indo para chamar tempo ponto de sono na variável segundos. Agora você vai notar uma coisa legal até PyCharm fez aqui para mim é que não importamos o livro do módulo de tempo porque, você sabe, ele está prontamente disponível. Quero tipo de reconhecer isso como uma opção que estávamos usando, ele realmente fez o importante para mim, mas caso contrário, claro, você sabe, certifique-se de importar o módulo de tempo. Certo, então vamos dormir pelo número de segundos que passamos na inicialização aqui. E então vamos apenas substituir o método run para chamar sleep, um método literal que acabamos de definir aqui. Certo, voltando para a nossa função principal, não precisamos mais do encadeamento e colocar aqui, acho que você vai nos ver novamente. Nós vamos, de trabalhadores ponto trabalhadores sonolentos, nós vamos importar o nosso trabalhador da cidade. E de trabalhadores ponto quadrado de algum trabalhador que estamos indo para Concord R-quadrado algum trabalhador. Tudo bem, então agora nós podemos substituir a criação deste loop aqui em vez de apenas inicializar nossa classe. Então nós vamos ter nosso trabalhador sonolento ser um exemplo de trabalhador sonolento. E vamos querer esperanças que vão para baixo. Aqui. Temos r ao quadrado, algum trabalhador, que vai ser uma instância da raiz quadrada algum trabalhador. E nós vamos ter o valor máximo aqui como o parâmetro de entrada. E o que vamos fazer agora para a junção é para os tópicos atuais. Vamos renomear isso para caroços de trabalhadores atuais. Tecnicamente a mesma coisa que temos aqui. Vamos manter o controle do nosso trabalhador que inicializamos aqui. E novamente, nós vamos apenas chamar o método join aqui para tipo de bloco até que esta execução deste feito. E depois vamos fazer a mesma coisa pelo nosso trabalhador sonolento. E aqui estão, segundos serão os segundos que eu fornecerei aqui. E isso podemos comentar para que possamos referenciá-lo em um segundo. E novamente aqui nós podemos apenas mudar isso para ser nossos trabalhadores atuais, que vai incluir cada uma das instâncias que temos aqui. E então vamos chamar Dot Junte-se novamente aqui. Tudo bem, então vamos em frente e executar isso. Então. Eu vou reconhecer que AMI, nós deveríamos estar fazendo exatamente a mesma coisa. E parece que encontramos um problema aqui. Então vamos ver onde está o problema em nossos métodos de junção aqui para dizer que não podemos nos juntar a uma ameaça antes de ela começar. Então provavelmente esqueceu de iniciar o fio interno aqui porque não chamamos mais aqui. Então vamos tentar isso mais uma vez. Tudo bem, lá vamos nós. Então nós temos nossa saída de execução aqui, e nós temos nosso sono, que atualmente é apenas três segundos desde sempre. Ainda tem essa sintaxe aqui, o menos dois. Então nós podemos ver aqui nós estávamos apenas, você sabe, neste caso, foi bastante simples. Nós só pegamos as duas funções dela aqui e colocamos cada uma delas em uma classe separada, o que, claro, para este caso, não faz muito sentido. Mas se você está fazendo coisas complexas como, você sabe, você quer escrever valores específicos em um banco de dados. E parte desse processo é estruturar todos os valores e formatá-los para que eles estejam na estrutura certa e, em seguida, fazer upload para o banco de dados. Então, se você tem um trabalhador de banco de dados específico pode apenas colocar os valores brutos e ele irá apenas estruturar os dados para você. E então faremos o upload. E tudo isso é meio que escondido de nossa função principal é cuidado dentro de cada classe em si. E, claro, aqui ainda estamos chamando o ponto junta-se em cada um desses apenas para tipo de bloquear a execução. Agora, podemos ver aqui ou não podemos construir. Veremos em um segundo. Lembre-se que tínhamos esses parâmetros Dan e ainda podemos fazer a mesma coisa porque estamos transmitindo os argumentos de palavra-chave. Podemos tornar o Damon verdadeiro. E então porque nosso trabalhador sonolento aceita todos esses argumentos de palavra-chave e os passa adiante, ele vai levar isso porque é um argumento de palavra-chave ou encontrar um valor específico, ele vai pegar isso e passá-lo para o pai classes, que neste caso é apenas o fio. Então ele vai definir o parâmetro daemon como true, que é claro que podemos ver o efetivo se removermos a chamada join aqui. Então vamos em frente e apenas executar isso mais uma vez apenas para tipo de ver o efeito de adicionar esse parâmetro de argumentos de palavra-chave no topo aqui. Então você pode ver aqui o parâmetro stamen foi então passado para o pai porque nós não estamos mais chamando o método join, nós temos exatamente a mesma coisa que vimos na lição anterior. Outra coisa que também poderíamos fazer é se quiséssemos que todas essas classes fossem sempre daemons. Também podemos definir o parâmetro daemon aqui, que terá o mesmo efeito. Exceto, claro, neste caso, a lógica está escondida de nós, o que pode não ser a melhor coisa, e nós realmente não temos muito controle sobre ela a menos que saibamos especificamente o que estamos procurando e atualizamos o atributo da classe em si. Mas, na verdade, algo importante a saber é que o parâmetro daemon precisa ser definido antes de chamar o método start. Então, porque também estamos chamando start aqui, se tomarmos nosso worker e definir Daymond para ser falso, ele não vai funcionar porque o parâmetro úmido precisa ser definido antes de iniciar o thread, que veremos em um O segundo aqui. Então, sim, lá vamos nós. Nós recebemos o erro para isso. Então, claro, você sabe, esconder isso não é a melhor coisa e é melhor se quisermos fazer isso, passar com a opção de argumento de palavra-chave que temos aqui. E neste caso, nós estamos apenas tornando-o um pouco mais limpo porque essas funções, primeiro lugar, não estão mais aqui, mas existem métodos da classe em si. E, você sabe, toda essa lógica é tipo passada para cada um dos diferentes trabalhadores entre aspas que temos aqui, todos eles tipo de fazer seu próprio trabalho separado, responsável por uma coisa separada ou específica. E então nós apenas dizemos, tudo bem, nós vamos correr, este trabalhador vai fazer essa coisa. E nós não chamamos a junção no final aqui. Vamos executá-los como operário. Vai fazer uma coisa específica. E realmente o programa principal é apenas para a ordem de execução e lógica geral. Considerando que todos eles gostam de grandes coisas de processamento. Não precisamos desordenar este arquivo e torná-lo muito grande. Nós podemos tipo de colocar cada um desses em arquivos separados ou em classes separadas aqui. E então, você sabe, se precisarmos olhar para a lógica específica, então tudo estará contido neste arquivo. Qualquer coisa relevante para a execução de cada uma dessas classes. 5. Criada um leitor de Wikipedia: Tudo bem, então agora que nós meio que criamos o básico de ter nossas aulas de encadeamento. Vamos em frente e saltar para o projeto real que queremos estar fazendo para tipo de implementar este threading e uma maneira mais útil. Então o que vamos fazer é pegar a lista de empresas S e P 500 nesta página. E nós vamos apenas percorrer todos esses símbolos. E então, para cada símbolo que temos aqui, vamos apenas visitar a página correspondente do Yahoo Finance. E nós vamos apenas extrair este preço atual aqui. E então vamos salvar essas coisas em um banco de dados. E então o processo que temos aqui é basicamente temos três coisas acontecendo que podem funcionar de forma independente. E vai haver um monte de coisas de rede acontecendo que realmente não queremos ser bloqueados. Então a primeira coisa que podemos fazer é pegar a lista de empresas daqui. E o que isso implica é apenas um pedido para aqui. E então apenas rolando através desta tabela e sempre apenas tirando a primeira entrada. Uma vez que temos cada uma dessas entradas, podemos então fazer uma solicitação aqui para o site e obter esse valor. Então isso é apenas uma solicitação de rede lá esperando por esse valor, tipo de extraí-lo. E uma vez que temos esse valor, podemos inseri-lo no banco de dados. Então podemos ver que isso provavelmente seria um aplicativo muito bom para threading se quisermos fazer isso o mais rápido possível, porque há um monte de coisas de rede acontecendo, você sabe, carregando páginas esperando por ele, inserindo no banco de dados, aguardando a confirmação. E não há realmente um monte de tarefas de CPU acontecendo. Então, sim, para fazer isso, vamos começar escrevendo a classe que nos permite extrair as entradas daqui. Então, em nossos trabalhadores, eu vou criar um novo trabalhador aqui. E vamos chamá-lo de trabalhador Wiki. E para isso, vamos usar a biblioteca de solicitações para realmente fazer as solicitações. E também vamos usar a Beautiful Soup. Se você não está familiarizado com Beautiful Soup ou se você meio que esqueceu sobre isso e certifique-se de apenas verificar a classe de desmantelamento web novamente. Mas, caso contrário, a biblioteca é bastante simples. Então, só estou indo em frente com isso aqui. Deve ser relativamente simples seguir adiante. Vamos ter a nossa classe de trabalho wiki aqui. E vamos ter o nosso método de inicialização. E realmente o que podemos fazer aqui é, por enquanto, podemos apenas codificar isso para ser URL que queremos limpar. Vou copiar isso. E realmente quando criamos nossa classe, vamos tudo o que vamos fazer é ter seu yuan ou L, o, você sabe, esse atributo de classe. Então a próxima coisa que vamos fazer é criar um método de classe que vai ser obter empresas S e P 500. E o que isso vai fazer é que está indo muito bem. Como o método indica, vai conseguir a empresa para nós. Então vamos fazer um pedido. Vamos usar a biblioteca de solicitações, fazer uma solicitação GET para o nosso URL aqui, assim. E nós vamos apenas assumir que tudo está acontecendo, mas nós podemos apenas ter aqui e como se nosso código de status não é um 100 e eu vou devolver uma lista vazia e talvez possamos imprimir como eu não consegui. E árvores, você sabe, que seja. Isso é meio básico. Claro que você pode estender isso a todos os códigos de status diferentes que você quer se preocupar ou até mesmo fazer algum registro aqui, mas nós vamos ter isso apenas pelo mínimo. E então vamos usar, vez de ter tudo no mesmo método, vamos apenas ir em frente e criar um segundo método que vai realmente extrair símbolos da empresa. E isso vai levar na página HTML. E este método aqui vai ser a coisa que realmente vai ser responsável por obter cada um desses símbolos. Então vamos em frente e olhar para a fonte da página, que você pode fazer clicando com o botão direito do mouse aqui e ver fonte da página ou Command Alt J. E estamos procurando, Vamos apenas ir em frente e obter uma compreensão da estrutura. Então vamos procurar o primeiro símbolo aqui, que vai ser apenas m. E se nós meio que derrubar isso, esta é a tabela que estamos procurando. E esta mesa realmente muito agradável como podemos ver. Então há uma ideia associada a esta tabela. E se nós apenas olharmos isso, então nós podemos ver que este é o único ID para esta tabela. Então não há “ Olhe para nós “ou algo assim também, o que é muito bom. Então, sim, vamos em frente e criar nossos lindos loops. instância Beautiful Soup, que vai tomar a página HTML. E nós vamos usar o L X. Eu vou analisar. Vamos colocar isso aqui porque se não colocarmos isso aqui, vamos receber um aviso ou nem mesmo um aviso, como uma notificação. Podemos deixar de fora por um segundo só para ver. Mas sim, apenas especificando isso para que não tenhamos aquele registro, o que pode ser um pouco irritante. Tudo bem, então a próxima coisa que temos que fazer é encontrar esta tabela de conteúdo primeiro, e então nós vamos fazer loop sobre esta tabela. Então nosso conteúdo ou nossa mesa vai ser sopa ponto encontrar. E nós vamos encontrar pelo ID, que vai ser os constituintes. E eu vou passar por isso um pouco mais rápido já que isso é mais como uma coisa de raspagem de web, não necessariamente focada no encadeamento, mas apenas para que tenhamos um trabalhador disponível para nós que possa realmente obter esses conteúdos para que possamos continuar usando-os. Então esta é a nossa mesa. E agora que temos a nossa mesa, queremos rever todas as fileiras. Então, nossas fileiras de mesa. Se entrarmos em nossa tabela, vamos encontrar todas as marcas de linha da tabela em nossa tabela aqui. Então podemos ver que há um no cabeçalho, e então há para cada linha, temos um aqui no corpo. E então podemos fazer loop sobre nossas linhas de tabela. Então, podemos dizer para a linha da tabela em uma tabela linhas e vamos pular o primeiro. Porque você vai notar se você está nos testando que o primeiro está realmente no cabeçalho aqui. E é claro, você sabe, não há nenhum símbolo para extrair aqui, então vamos pular o primeiro. E então para cada linha da tabela, vamos extrair o símbolo, que vai ser, vamos encontrar a primeira tag T d, que podemos ver aqui. E daqui vamos tirar o texto. E nós também vamos remover o caractere de nova linha no final aqui. Então estes serão os nossos símbolos. E agora podemos coletar esses mentalistas e devolver toda a lista. Ou também podemos usar um gerador e apenas sentir ou símbolo. E, a partir daqui, podemos dizer rendimento a partir de ponto, extrair símbolos da empresa. E eu só vou precisar passar a página HTML DOM, que vai ser apenas a parte de texto da nossa resposta aqui. Certo, então uma coisa a notar na verdade é que não estamos usando uma propriedade de classe aqui. E então o que podemos fazer é que podemos realmente fazer isso um método estático que pertence a, é basicamente compartilhado entre todas as instâncias da classe. E então nós não, porque nós não estamos usando qualquer propriedade classe é em si mesmo. Ok. Então esta vai ser a nossa trabalhadora da Vicki. Mas é claro, vamos em frente e testar isso. Agora porque estamos usando a Sopa Bonita. Realmente. Neste ponto torna-se, haverá, será um pouco mais agradável se quisermos reutilizar isso mais tarde. Só para garantir que todo o nosso ambiente, todas as nossas bibliotecas e outras coisas estejam contidas. Vamos criar um ambiente virtual. Então eu vou para python menos m, então, então, alguém para criar um ambiente virtual. E o diretório atual que será chamado Ben. Hit Enter, que vai criar nosso ambiente virtual para nós. E isso basicamente nos dá um tipo de instalação recente do Python que podemos usar, que é apenas se nós ativá-lo, ele se torna um pouco mais agradável porque então nós estamos meio conscientes de que bibliotecas estamos usando e nós podemos fazer um arquivo requisitos específicos para que tudo é tipo de auto-suficiente e não dependente da nossa configuração atual do sistema. Então vamos em frente e ativar nosso ambiente virtual. E se nós apenas entrarmos em Python, por exemplo, agora você pode ver onde em nosso ambiente virtual e eu tentar importar essa classe, nós estamos realmente tendo um problema porque agora nós não temos uma super tempestade bonita. Então vamos dizer de workers dot wiki, worker, vamos importar chave 0 e até mesmo solicitação não está instalado. Então vamos em frente e fazer pedidos de instalação de pip. E porque estamos em nosso ambiente virtual, na verdade vai usar a versão pip do nosso ambiente virtual. Então você pode ver aqui o PIP para ambiente virtual aqui. E a próxima coisa que queremos fazer é também instalar a Beautiful Soup. Então, para fazer isso, vamos digitar pip, instalar o OH, para sopa completa para. Não há nenhum tipo aqui. Ok, ótimo. E sim, estas são as duas bibliotecas que não deveríamos precisar. Então podemos ir em frente e tentar isso. Mais uma vez e ótimo. Lá vamos nós. Funciona. Podemos testar isso em um segundo. Mas vamos apenas escrever nossos pacotes atuais em um arquivo de requisitos para que, se necessário, possamos recriar isso mais tarde. Tudo bem, então vamos em frente e testar este wiki e trabalhador. E nós vamos fazer uma instância de n. E então nós podemos dizer para símbolo em McKee, ponto trabalhador obter S e P 500 empresas, apenas chamando nosso método de classe aqui. Vamos em frente, imprimir um símbolo, e depois interrompê-la. Geração de um erro de digitação aqui. Tudo bem. Vamos imprimir o símbolo e depois vamos quebrar. E sim, aqui vamos nós. Então isso é, porém, um aviso de que estávamos recebendo esse tipo de como escolher um 12 específico. É por isso que você pode simplesmente colocar L, x e L lá dentro. Apenas deixe que não os faça. Tudo bem? Ok, então olhando para o nosso simples, tudo bem, então nós temos o primeiro. E então vamos ter uma lista de símbolos. E vamos fazer a mesma coisa. Mas vamos anexar cada símbolo em nossa lista simples para ter certeza de que não estamos recebendo nada extra, você sabe, no final ou algo assim. E então vamos olhar para o comprimento do nosso simbolizado, que tem 505, que é na verdade o número de empresas neste. Eu sei que é meio confuso porque diz 500 e na verdade são 505. Mas isso é ótimo porque era exatamente o que estávamos esperando. E dois, sem confirmação extra. Podemos ver o último. Role todo o caminho para baixo. Uma vez longe demais. Lá vamos nós. Certo, Perfeito. Então agora temos a nossa classe para obter os símbolos. Agora, novamente, nós meio que passamos por isso um pouco mais rápido só porque novamente, queremos ter certeza de que nos concentramos em encadear aqui e não especificamente em construir policiais do oeste. Então, sim, se você está familiarizado com sopa bonita e lenços corte, ótimo. E se você não estiver, você provavelmente teria sido capaz de acompanhar de qualquer maneira, já que nossa sintaxe é bastante simples aqui e nós estamos apenas passando por diferentes elementos HTML. Mas se você quiser uma atualização sobre isso, se você quiser aprender esta mistura, você vá em frente e apenas agite a aula de desmantelamento web novamente. Mas sim, então agora temos nosso trabalho wiki estão disponíveis para nós, que vai ser a primeira coisa, claro, que precisamos. Que basicamente vai nos ver com todos os nossos valores que podemos usar para, você sabe, mais tarde, procurar as empresas individuais por meio de manipulação deste URL aqui. E então nós também podemos ir em frente e uma vez que nós extraímos este valor aqui, nós podemos então ir em frente e enviar isso para um banco de dados. Então vamos parar aqui por agora e depois continuar com isso na próxima lição. 6. Como criar um leitor de finanças no Yahoo: Tudo bem, então agora que temos nossa configuração wiki worker, vamos em frente e escrever a classe, que vai ser uma classe encadeada, que vai extrair o preço usando este URL do Yahoo Finance aqui. Tudo bem, então eu também vou deletar esses dois trabalhadores aqui porque, bem, nós não precisamos mais deles. Então vamos em frente e deletar estes rapidamente. Vamos criar um novo trabalhador aqui, que vai ser Biao que financia o preço. Vamos chamar isso de trabalhadores do Yahoo Finance. E, em seguida, aqui nós vamos primeiro importar o threading porque nós estamos usando ele. Mas então ele vai ter um trabalhador de preços yahoo Finanças, que vai herdar de threading dot thread, como fizemos antes. E, em seguida, em nosso método de inicialização, nós vamos apenas certificar-se de inicializar isso para. E nós também vamos aceitar argumentos de palavra-chave que vamos passar para nossas classes pais aqui. Tudo bem, então isso é o que tínhamos antes. Agora vamos também nos certificar de iniciar o tópico para que você saiba que vamos chegar a esse ponto. E então nós também vamos ter o, vamos sobrescrever o método de execução, mas defini-lo em um pouco. Está bem? Então, do que precisamos? Bem, também precisamos aceitar o símbolo que queremos ter. Tipo de querer salvar esse símbolo como um atributo de classe. E então nós também precisamos da URL base que queremos usar, que é basicamente vai ser tudo, exceto para esta última parte. Então este vai ser o nosso URL base. E então, no final aqui, nós podemos, bem, na verdade, nós podemos ter nosso ano base apenas definido aqui. E, em seguida, vamos definir a URL real para ser a nossa URL base. E vamos usar strings formatadas aqui. E então nós vamos apenas adicionar o símbolo no final aqui. Então, sim, nós vamos ter apenas o nosso ano base. Serei a primeira parte aqui. E então aqui, nós vamos adicionar sobre ela são semelhantes no final. E então realmente isso aqui vai nos dar qualquer que seja o símbolo. Basicamente, vai dar-nos o mesmo resultado. É apenas uma maneira mais limpa na minha opinião de expressar isso. Certo, então agora temos nosso worker aqui, e agora queremos sobrescrever o método run, que é basicamente o que temos que fazer aqui é OK, então agora temos esse mictório. Então, mais uma vez, precisamos extrair esse preço aqui. Então vamos para o HTML e vamos tentar encontrar isso. Então nós temos isso aqui em, é na verdade no título. Isso é muito conveniente. Então vamos ver se é em outro lugar também, mas já podemos pegá-lo de lá. Também está aqui. E vamos ver se está bem. Então também retornou no script em algum lugar. Então, há maneiras diferentes de fazermos isso. Um deles é claro, podemos extraí-lo. Onde foi isso? De? Onde apareceu como podemos extrair daqui. Mas se clicarmos com o botão direito do mouse e copiarmos o XPath, e vamos dar uma olhada nisso. Sim, então não parece particularmente limpo. Não há identificação específica ou qualquer coisa que possamos usar aqui. E como ele também está incluído no título, nós também não podemos apenas extraí-lo de lá. Isto é claro, um pouco dependente é assumir que Yahoo tipo de manter este formato. Mas, você sabe, se, se eles mudarem, como se eles mudarem também este formato aqui em cima, nós também vamos ter que adaptar nosso arranhão ou de qualquer maneira. Então, vamos apenas seguir com a opção mais simples por enquanto. Vamos apenas extraí-lo do próprio título aqui. Tudo bem. Então, novamente, vamos importar da pasta BS. Nós vamos importar E Beautiful Soup. E vamos em frente e apenas testar isso ou notícias embora. Também precisamos importar o módulo de solicitações. E vamos em frente e usar isso para testes. Então, vamos definir nossa URL aqui. Nós vamos importar solicitações, vai dizer, tudo bem, é igual a ponto de solicitação obter nossa URL. E então nós vamos ter nossa sopa ser um exemplo de Beautiful Soup, tomando o texto de nossos pedidos. Então eu tenho um erro de digitação aqui. Eu não era importante, importante. Tente isso de novo. Vamos fazer o título da sopa, o que nos permite acessar isso diretamente, certo? Então, felizmente, ele faz, parece que este conteúdo é gerado dinamicamente, mas tudo bem. Vou fazer isso de uma maneira diferente. Vamos usar a biblioteca XML L em vez disso. E realmente nós vamos apenas usá-lo para uma coisa muito simples, que será apenas certificar-se de que podemos usar XPath uma vez que ele não é suportado atualmente com Beautiful Soup. Então vamos dizer de x, eu sou L, x e L, e vamos importar HTML. Então eu, é claro que não o temos instalado. Então vamos em frente e rapidamente instalar a barraca L x L. Lá vamos nós. Vou escrever isso para um requisito. Coloque nosso Python novamente, vamos tentar importar isso. Lá vamos nós. E vamos pegar, não preciso mais de uma bela superior. Vamos em frente e ter o nosso você está indo para ir enviar um pedido e sondar pedidos. Tudo bem. E então nós vamos dizer, bem, nosso conteúdo de página que podemos chamá-lo vai ser HTML a partir de string. Então nós estamos indo apenas para importar HTML aqui a partir de L XML. Isso só vai nos ajudar a analisar usando XPath. Estou novamente, você vai notar que a sintaxe é muito simples, então não precisa estar familiarizado com esta biblioteca. Nós só vamos usar basicamente esses dois métodos a partir dele. Primeiro, vamos colocar aqui a string HTML, que vai ser salvo aqui. E então isso tem um método de caminho ex pat x que vamos usar. E então o que temos que fazer aqui é agora temos que obter o XPath para isso, que podemos fazer muito facilmente clicando com o botão direito do mouse em Copiar XPath. Então, uma vez que encontramos este elemento aqui, que podemos apenas fazer pesquisando assim, você pode clicar com o botão direito do mouse em Copiar XPath, e então ir em frente e colocar isso aqui. E lá vamos nós. Então podemos ver se podemos acessar o primeiro elemento, o texto, então vamos ser capazes de extrair o valor aqui assim. Tudo bem, então vamos em frente e implementar. Então testamos isso para ter certeza de que temos algo que está funcionando. Então vamos em frente e fazer isso de novo. Nós vamos ter o nosso bem, na verdade nós podemos apenas copiar isso, então já que nós já fizemos isso. Então vamos primeiro emitir nosso pedido, que vai ser através disso. E então temos o conteúdo da nossa página como este. E depois queremos ter um preço como este. E nós não estamos fazendo um monte de manipulação de erros aqui. Por exemplo, o que acontece se não obtivermos uma resposta aqui? Este valor não pode ser convertido em um flutuador ou qualquer outra coisa. Então, é claro, você sabe, se você quiser tornar isso mais robusto, você pode adicionar a verificação de código de status aqui como fizemos em nosso trabalhador wiki. Você pode adicionar instruções try-except para lidar com casos diferentes onde você pode nem sempre estar recebendo um valor float. Mas apenas para manter isso simples, vamos apenas mantê-lo assim sem fazer muita manipulação de erros. Então agora temos nosso preço, e então podemos apenas ir em frente e apenas imprimir nosso preço por enquanto. Tudo bem, então vamos voltar para a nossa principal função aqui. E agora vamos mudar isso um pouco e importar nossos dois trabalhadores e apenas tê-los trabalhando juntos um pouco. Então, aqui queremos importar o trabalhador de preços do Yahoo Finanças. Então a primeira coisa que vamos fazer é criar uma instância do nosso trabalhador wiki. E nós vamos dizer para símbolo no trabalhador Wiki, não obter empresas S e P 500. Isso só vai nos dar um símbolo de cada vez. E agora vamos criar uma instância do operador de preços do Yahoo Finance. E o símbolo que vamos passar aqui é apenas diretamente vai ser o símbolo que temos aqui. E então se quisermos e mantermos uma lista dos nossos trabalhadores atuais, como fizemos. Escrevido são Yahoo Finanças, trabalhador de preços. E, em seguida, basta usar o método join aqui. E tire isso. Ainda podemos distrair o tempo. Tomou e renomeie nossa variável aqui para descartar o tempo de reinicialização. Tudo bem, então precisamos ter certeza que usamos a instância de seu trabalhador wiki aqui, não apenas a definição de custo em si. Então vamos rever o que fizemos. E basicamente nós meio estamos aplicando o que aprendemos para encadear aqui agora usando nossos dois trabalhadores. Então, o primeiro que temos é o nosso trabalhador wiki, que novamente, se passarmos por cima, ele tem o método principal que vamos usar aqui, que vai obter as empresas S e P 500, que vai apenas enviar este solicitação. E para este pedido dos elementos da tabela, É isso, eu só vou extrair o primeiro elemento, que assumimos que vai ser o símbolo. E que vamos usar como entrada longe Yahoo Finanças preço trabalhador. E para isso, vamos enviar uma solicitação para este URL. Nós estamos indo para extrair do HTML usando esta classe HTML XML aqui. Nós só vamos usar isso para que possamos realmente obter o XPath tipo de ter este ser uma maneira fácil de obter o XPath um extrair o preço a partir daqui e convertê-lo em um flutuador. Então vamos rolar sobre essas listas de empresas que temos aqui. E para cada símbolo que obtemos, vamos então criar um thread, que vai criar este pedido. E então ele vai apenas imprimi-lo para a saída por enquanto. Então vamos rastrear o tempo de execução como fizemos antes. E aqui estamos chamando juntar-se no final, apenas para que basicamente tudo seja bloqueado até que cada thread termine. E nós nem precisamos fazer mais nada aqui porque ele tem o, estamos substituindo o método Run padrão, que acontece logo após iniciarmos o worker. Então, sim, antes de executarmos isso, eu quero implementar mais uma coisa que só vai abrandar nosso perímetro um pouco. Vamos importar o tempo e vamos importar aleatoriamente apenas para que não enviemos spam. Vamos dizer que o tempo não dorme. Vamos dizer 200 pontos aleatórios aleatórios. Então isso significa que cada thread vai dormir entre 0 a 20 segundos, uma vez que isso gera um número aleatório entre 01. Então isso vai abrandar as coisas um pouco e vai fazer o nosso programa funcionar. Bem, acho que neste momento, como um máximo de 20 segundos de algo dorme como 20 segundos. Podemos até empurrar isso para 30 apenas para, você sabe, não spam Yahoo enquanto estamos fazendo isso. Porque vamos mudar as coisas um pouco mais tarde para não gostar de gerar um trabalhador individual para cada símbolo que temos aqui. Mas sim, e na verdade eu quero implementar um cheque extra aqui, que será se nosso código de status for 200. Então, por enquanto, vamos parar. E, você sabe, parar execução para que nós não obter como span com mensagens de erro e outras coisas. Então vamos em frente e executar nossa função principal. Eu vou fazer isso no terminal desta vez porque eu tenho minha configuração de ambiente virtual aqui, que tem tudo instalado que eu preciso. Então vamos em frente e executar isso. E depois de esperar um pouco, lá vamos nós. Então nós temos os preços começando a vir aqui. Alguns nos interrompem. Mas sim, tudo está funcionando como pretendido. Agora, eu posso garantir que provavelmente há alguns erros aqui que nós não estamos pegando, que pode ser devido a uma variedade de razões com as quais deveríamos estar lidando melhor. Mas, por enquanto, vamos deixar isto como está por enquanto. Devíamos, pelo menos, ser como encerrar isto ou algo assim. Mas o que quer que seja por agora, vamos deixar como está, já que o objetivo principal disso era apenas configurar os threads para realmente fazer as solicitações separadas. Então, esses são os fios separados. Para que possamos fazer todas essas solicitações separadas para que possamos, você sabe, não estamos bloqueados por todo esse tempo de rede. Mas daqui para frente, vamos realmente ver como podemos tipo de limite e escalar e tipo de definir quantos trabalhadores queremos ter para que cada um tenha tudo isso ser um pouco mais estruturado em vez de apenas desova e thread individual para cada iteração que temos aqui. E isso também vai nos ensinar como podemos passar informações entre diferentes tópicos para que todas essas coisas possam ser executadas simultaneamente. Chegaremos a isso no próximo vídeo. 7. Quas e programador de mestres: Tudo bem, então, na última lição, nós meio que configuramos nosso trabalhador do Yahoo Finance bem como nosso trabalhador wiki, que tínhamos antes. E nós apenas percorrer todos os símbolos e enviamos pedidos e, você sabe, temos todos os preços que pudemos. Mas agora vamos sistematizar isso e torná-lo um pouco mais agradável. E o que vamos fazer é fazer com que estes sejam processos separados. Então, ao invés de percorrer o símbolo e, em seguida , para cada símbolo diretamente criando um segmento, o que vamos fazer é separar todas essas entidades. Então vamos percorrer todos os símbolos primeiro. E então vamos, sempre que tivermos um símbolo, vamos colocá-lo em algo chamado fila. E então teremos tópicos diferentes dos trabalhadores do Yahoo Finance que vão ler a partir dessa fila. Então nós meio que temos essa coisa intermediária. E então sim, novamente, aquela coisa que vamos usar chama-se fila. E realmente a idéia, ele, idéia aqui é que nós podemos pegar elementos e nós podemos colocá-los no Q. E assim, nós estamos meio que separando quão rápido ou lento diferentes threads estão correndo. Porque o Q pode se acumular e podemos colocar um monte de elementos. E então nossos trabalhadores podem, nosso trabalhador a jusante. Então, os que estão tirando dessa fila podem ler a partir da fila sempre que estiverem prontos. Então, dessa forma, nós também temos um pouco de, e vamos ver isso em um mais tarde. Nós temos mais controle sobre, você sabe, quantos trabalhadores de entrada nós gostaríamos de ter se pudermos escalar isso. Mas também quantos leitores da fila, quantos consumidores da fila queremos ter. Se notarmos que nossa fila está se acumulando muito rapidamente e está crescendo, então podemos adicionar mais consumidores. E se notarmos que nossa coisa ou o q está sempre vazio basicamente, então podemos realmente reduzir o número de consumidores porque não está realmente nos dando nenhum benefício ter tantos trabalhadores. Tudo bem, então para implementar uma fila, vamos usar a biblioteca multiprocessamento. E daqui vamos importar Q, isto. E então nós vamos criar uma fila, que vai ser o nosso símbolo Q, que vai ser uma instância de Q como este. E então o que vamos fazer é comentar isso por enquanto. Comente isto aqui fora. À medida que esfregamos os símbolos aqui, vamos apenas usar nosso símbolo q. e aqui vamos colocar o símbolo, então vamos inseri-lo na fila. Agora cues são thread-safe, o que é ótimo porque isso significa que podemos realmente usar o sistema de imposto threading. Tudo bem, e então, sim, isso é tudo o que temos que fazer dessa maneira. Colocamos elementos em nossa fila. Então, se executarmos isso e então podemos imprimir a fila no final. E há realmente um método get que podemos usar que apenas obtém o próximo elemento da fila. Então nós podemos executar nossa função principal apenas para tipo de ver os resultados disso. Então vemos que temos uma fila implementada ou uma instância do objeto aqui. E usando o método get, obtemos o primeiro valor da fila, que neste caso é o primeiro símbolo. Nós esperamos isso. Certo, então agora que estamos colocando esses elementos na fila, agora podemos ter um fluxo separado de processos que podem estar consumindo dessa fila. E é isso que os nossos trabalhadores do Yahoo Finance vão ser essencialmente. Mas também vamos mudar as coisas aqui um pouco. E em vez de ter os trabalhadores de preços do Yahoo Finanças fazer isso diretamente, nós estamos realmente indo para mudar isso para cima e nós vamos ter um agendador que vai cuidar do threading. E então nós vamos ter nosso próprio trabalhador de preços do Yahoo Finance apenas ser a classe que extrai as informações de preços. Mas terá uma classe diferente Kino responsável pela parte multiprocessamento. Então vamos chamar este o agendador de preços do Yahoo Finance. E isso vai ser uma instância de execução. E isso, na verdade, não será mais uma subclasse da classe de rosqueamento. Então aqui novamente, vamos inicializar isso. Vamos inicializar a classe dos pais. Nós também vamos permitir argumentos de palavra-chave. Opa, e passe isso para a classe dos pais aqui. Tudo bem, e então vamos substituir o método de execução. E aqui vamos ter um loop infinito. E basicamente o que vamos fazer nesse loop infinito é o que vamos ler da fila. E então o que precisamos aqui também é que precisamos de uma fila de entrada porque precisamos de uma leitura de uma fila. Então nós vamos fornecer que como um argumento de entrada aqui tem um argumento de inicialização. Vamos ter a nossa fila de entrada aqui. E então nós vamos ter o nosso próximo valor apenas ser auto-didacta fila de entrada. Novamente. Agora esta é uma operação de bloqueio, o que significa que ele vai bloquear isso, ou esta operação vai bloquear até que nós realmente obter um valor retornado. Chegaremos a isso mais tarde. Mas, basicamente, enquanto esse loop está sendo executado, ele só vai tentar continuar lendo da fila. E toda vez que ele obtém um valor, então ele vai continuar a execução. Então também o que queremos fazer aqui é porque temos um loop infinito aqui em algum momento queremos sair dele. Então, uma maneira fácil de fazer isso para dizer, tudo bem, se enviarmos o valor w1 e terminarmos, agora só queremos sair. Tirando isso. Se obtivermos um valor e este valor não for feito, vamos supor que é um símbolo. E então o que queremos fazer é que queremos ter uma instância do nosso trabalhador de preços do Yahoo Finance. E o símbolo que vamos passar aqui vai ser o nosso valor, porque vamos ter certeza que nosso Q upstream realmente coloca o valor aqui. E, em seguida, vamos também alterar este método de execução. Em vez disso, vamos renomeá-lo para extrair ou obter o preço do Spark. Vamos chamar de bom preço. Tudo bem? Então vamos chamar isso, e vamos dizer preço. E aqui, em vez de imprimir o preço, vamos em frente e devolver o preço. Então, vamos dizer que nosso preço é igual a usar a instância do nosso trabalhador do Yahoo Finance aqui, vamos obter o preço e realmente precisamos mover isso aqui para cima, iniciar o thread. E então F que queremos aqui nós podemos tipo de imprimir a imprensa por agora e mais tarde, nós realmente vamos colocar isso em uma fila diferente, que vai ser responsável, qual trabalhador a jusante vai ser responsável por inserindo no banco de dados. Mas, por enquanto, vamos apenas imprimi-lo. E Yang, não precisamos mais dormir aqui. Mas o que podemos fazer se quisermos é adicionar um pouco de sono no final aqui, já que não estamos realmente, isso não é como uma solicitação de API, então não estamos recebendo informações da API no cabeçalho é sobre como grandes limites ou algo assim e quantas solicitações podemos fazer. Então, para ser respeitoso depois de cada pedido, vamos dormir em qualquer lugar entre 01 segundos apenas para retardar o processo um pouco. Então, novamente, o que temos aqui é que temos nossa classe de agendador agora, que nós temos tipo Move para ser nossa master threading class. E isso vai levar uma fila de entrada como uma entrada. E então vamos começar o fio. E então ele vai basicamente entrar em um loop infinito. Ele vai continuar lendo a partir da fila até que ele lê o valor, em que ponto ele vai sair. E cada vez que ele obtém o valor e este valor não é feito. Ele vai criar uma instância da classe de preço do Yahoo Finance. Ele vai fornecer este valor como o símbolo. Desde consulta ou assumindo que é o que estamos recebendo desta classe aqui. E então nossos jovens trabalhadores de preços financeiros serão responsáveis por extrair o preço lá. E sim, é isso por enquanto. Então vamos em frente e assumir isso aqui. E vamos criar uma instância de antemão para que, você sabe, assim que começarmos a colocar valores até a fila, possamos realmente começar a consumi-la. Tudo bem, então crie uma instância do nosso calendário de preços do Yahoo Finance aqui. Não, você tem que se certificar de que damos a fila de entrada. Agora a fila de entrada que vamos usar vai ser o símbolo Q, já que este é o lugar onde ele deve estar lendo. Então, sim, agora só temos um segmento que estamos criando aqui. Vamos apenas criar uma lista para isso no caso de você querer ter mais, que faremos mais tarde em finanças, preço, agendador, aluguéis. E assim. E então nós podemos apenas tipo de manter este loop aqui, não precisamos mais disso. Tudo bem, então uma coisa que temos que fazer no final aqui é porque estamos aguardando o valor w1. Assim que terminarmos, certifique-se de que colocamos aqui feito. Para que nossa classe realmente vai sair, ou esse fio é realmente uma saída para fora. Uma coisa, é claro, que podemos fazer em vez apenas colocar um é se quisermos mudar isso mais tarde, que vamos muito em breve, vamos dizer para loops. Para quantos threads temos, vamos colocar um valor w1 para ter certeza que cada instância do nosso segmento está realmente indo para quebrar. Porque se colocarmos um valor aqui, porque estamos consumindo dessa fila, cada thread será apenas leitura de um valor. E uma vez que atinge esse valor para basicamente feito. Então, se tivermos vários threads e apenas um deles vê o valor w1, então digamos que temos quatro threads. Um deles lê feito do que os outros três tópicos não vão estar quebrando porque a fila está vazia e eles estão esperando por algo para ler. E isso está apenas bloqueando qualquer execução adicional para esse thread fora para todo o programa, apenas para esse segmento. Então eu sou, é por isso que nós queremos ter certeza de que nós apenas fornecemos valores feitos o suficiente aqui para garantir que cada instância da garganta que nós temos realmente irrompa. E sim, vamos em frente e executar isso. Este deve ser um pouco mais lento, já que neste momento só temos uma instância do nosso segmento. Isso é exatamente o que vemos aqui. Estamos apenas extraindo nossos valores e estamos colocando nossos valores na fila aqui. E uma vez que um valor começa, você sabe, está nesta fila, é quando nosso trabalhador aqui começa. Então ele já foi inicializado de antemão e já está começando a ser executado. E assim que inicializá-lo em entra neste loop, e então ele faz isso. E agora está esperando até que haja algo na fila. Uma vez que há algo na fila, ele vai ler a partir dele. Assim que o primeiro símbolo é colocado aqui, vai começar a ler a partir dele. Se quisermos, podemos ver que podemos adicionar um sono e vamos apenas dizer que dorme por dez segundos. E podemos dizer inserindo primeiro símbolo. Então vamos dar uma olhada nisso. Então vamos inserir o primeiro símbolo e, em seguida, vamos esperar para ter um símbolo inserido. Mas assim que ele é inserido, há um valor no agendador de preços Q e R Yahoo Finance que já está em execução assim que algo está na fila, então ele pode tirá-lo da fila aqui e pode começar a fazer o seu trabalho. Então, assim que algo está na fila, então ele começa a fazer seu trabalho. O que é muito bom porque este tipo de torna todos os processos independentes um do outro. Certo, então é claro que podemos tirar isso. E agora, se quisermos fazer isso um pouco mais rápido, tudo o que temos que fazer é apenas, sabe, digamos, “Nº”, “Yahoo Finance”, “trabalhadores de preços”. Digamos que queremos ter para os trabalhadores. E podemos dizer que para quantos trabalhadores eles querem ter, você sabe, nós apenas criamos um desses. E então agora nós teríamos neste caso, para os trabalhadores que estão executando cada um deles esperando para ler a partir da fila. E sempre que algo é colocado na fila aqui, eles vão começar a consumir e eles vão começar a fazer o seu trabalho, como podemos ver aqui. E nossas filas são seguras para threads, que é muito bom porque, você sabe, nós não temos que lidar com nenhum dos problemas que falamos antes. E ok, então agora estamos recebendo alguns bons valores aqui, ok, que nós temos que lidar com. Então o preço é muito alto. Então, uma coisa que podemos fazer aqui é fazer alguma formatação e chamar isso de preço bruto. E parece que há uma vírgula para milhares. Então nós vamos apenas substituir isso por uma string vazia como esta. Só para consertar onde não estava, como essas coisas de formatação. Então, sim, nós chegamos a um ponto realmente agradável porque nós meio que temos essa independência entre nossas diferentes pistas. Lá vamos nós. Assim, podemos ver que os milhares também estão funcionando. Nós temos essa independência entre nossos diferentes tópicos porque uma pode, isso não é mesmo, quero dizer, isso seria parte de nossa linha principal. É só colocar valores na fila. E sempre que algo é colocado, temos nossos diferentes trabalhadores aqui que estão prontos e disponíveis para começar a consumir a partir dele. 8. Como criar um trabalhador de postares: Tudo bem, então agora vamos em frente e trabalhar no nosso trabalho de inserção de banco de dados. Então eu vou usar meu banco de dados Postgres local. Estou usando grupo de dados aqui, mas é claro que você pode usar qualquer ambiente de codificação, você sabe, você gosta mais ou codificação IDE. Sim, Se você não é super fresco sobre como criar seu banco de dados Postgres, apenas certifique-se de ir em frente e verificar o curso SQL. Mas caso contrário, sim, apenas gire um servidor Postgres local. E então eu vou apenas usar o banco de dados Postgres padrão aqui também. E nós estamos apenas indo para criar uma tabela em nosso banco de dados Postgres estão apenas indo para inserir esses valores em. Então eu vou dizer criar tabela, e vamos chamar isso de preços. E nós vamos ter uma coluna de identificação que vai ser cereal e nós vamos apenas ser a nossa chave primária. E então nós também vamos ter o símbolo, que vai ser a, apenas tem b, o texto. E então nós vamos ter preço, que vai ser um número de ponto flutuante. E então nós também vamos ter o tempo, ou vamos chamar este tempo de inserção. Desejo apenas vai ser um, bem, vamos apenas ter que ser um carimbo de data/hora. Tudo bem, então é uma tabela de banco de dados bastante simples que estamos tendo aqui é apenas vai ser uma tabela individual aqui com o indivíduo ou para ser uma única tabela com os preços aqui vamos ter nossa coluna ID, que vai ser apenas em série como nossa chave primária. E então apenas um símbolo, bem como o preço e o tempo. Ou talvez em vez de inserir o tempo, teremos apenas extraído o tempo. Então, a hora que pegamos no site. Tudo bem, então vamos em frente e executar isso. E lá vamos nós. Voltando ao nosso diretório de threading aqui, ele criou um novo trabalhador, que será o nosso trabalhador Postgres. Tudo bem? E aqui vamos ter duas coisas. Só vai ser o nosso programador mestre Postgres, que vai ser uma instância do segmento de rosqueamento como tínhamos antes. Assim como fizemos para o trabalhador de preços do Yahoo Finance. E vamos exceto argumentos de palavra-chave, bem como uma fila de entrada. E então vamos apenas inicializar os pais transmitindo argumentos de palavra-chave. Defina a fila de entrada para ser a fila de entrada que tiramos da inicialização. E, em seguida, substitua o método de execução. Assim como fizemos para o trabalhador do Yahoo Finanças. E vamos dizer aqui, novamente, vamos estar olhando para a nossa fila de entrada. E vamos esperar até que eu receba o próximo valor. E sem valor é feito, e nós vamos sair do nosso ciclo. Tudo bem, Então, isso é basicamente vai ser a essência do nosso anfitrião Chris master scheduler, exatamente o que fizemos aqui para o trabalhador Yahoo Finanças. E, claro, para não esquecer, queremos ter certeza de que iniciamos o thread T2 uma vez que inicializamos ou criamos uma instância da nossa classe. Certo, então agora precisamos fazer a outra coisa, que será apenas tratar nosso trabalhador Postgres, que será o responsável por inserir os dados em nosso banco de dados aqui. E este no método de inicialização. Isso vai levar o símbolo, bem como o preço como entrada, e talvez também o tempo extraído. Ele só vai tomar todos esses valores como entrada. E nós podemos limpar isso em um pouco e fazer, ter isso ser uma espécie de dicionário como uma entrada ou algo onde você pode obter os valores fora de. Frenologista, deixe isso como está. Então vamos ter o nosso símbolo B, o símbolo de entrada. Nós vamos ter o nosso preço ser, o preço de entrada, vai ter. O extracto do tempo. Se você extrair um tempo aqui, ok? E agora nós basicamente precisamos do método que vai ser inserido no banco de dados. E isso vai fazer a nossa inserção. E em nossa inserção aqui nós basicamente precisamos, em primeiro lugar, nós precisamos criar a consulta de inserção. E então o que precisamos fazer é que precisamos executar a inserção. Então, vamos ter o Criar, inserir consulta ser um método separado. Só vou criar a consulta para nós para que possamos ter isso de volta. E então vamos executar a inserção. Então, para criar a consulta, vamos fazer é, vamos apenas fazer isso usando SQL bruto aqui. Vamos dizer inserir em preços, valores. E então nós vamos, bem, existem diferentes maneiras de fazer isso. Um deles é que podemos usar e, f formatação aqui para dizer, bem, é também definir aqui o interesse da ordem da coluna para ser seguro, preço e tempo extraído. Vamos nos certificar de que isso se encaixa com nossa sintaxe. Então coloque isso em uma nova linha só para deixar mais claro. Então, novamente, a primeira maneira que podemos fazer isso é usando as cordas f. Como este. Apenas tipo de formatação nos valores diretamente. Como este. Isto está tudo bem. Porque estamos fazendo isso internamente. E não há como entrada externa, mas não é o melhor. Na verdade, há uma maneira melhor de fazer isso, que é ter a formatação de texto tipo de ser feito com para nós. E nós apenas fornecemos como aqui vai ser o símbolo que irá fornecer mais tarde. Aqui vai ser o preço, e aqui vai ser o tempo extraído. E então nós também não precisamos ter a corda f aqui. E sim, esta é basicamente a consulta SQL que é, você sabe, que precisamos ter. Não é muito, mas está tudo bem. E então nós vamos apenas transformar essa consulta. Então, novamente, a primeira coisa que vamos fazer aqui é que vamos ter inserir consulta apenas ser criado para nós. E agora nós realmente precisamos executar a inserção de banco de dados na inserção de banco de dados, precisamos configurar uma conexão de banco de dados. E assim, para fazer isso, vamos usar uma biblioteca chamada Alquimia SQL, que só vai nos ajudar muito. O que só vai nos ajudar muito como configurar a conexão de banco de dados, executar esses comandos SQL. E é realmente como uma biblioteca geral que podemos usar para se conectar a bancos de dados. Mas eu vou te mostrar o lugar como o essencial em um segundo aqui. Mas a primeira coisa que precisamos fazer é instalá-lo. Então nós vamos pip instalar alquimia SQL como este. E então em um segundo, então nós também vamos pip instalar tortas P. E eu realmente espero que eu estou espinha está certo. Mas se não, procurarei em um segundo. Binário de torta. Tem um erro de digitação. Então vamos tentar isso. E é alto. Lá está ele. Então isso é pip install pi, psi. Sempre tenho mais rasa lembrando a pronúncia dele, que é, eu nunca posso escrevê-lo. Policial G para binário. E isso vai nos permitir configurar as conexões Postgres. Então vamos instalar a alquimia SQL. Nem precisamos importar psicocópico2. Nós vamos instalar a versão binária porque às vezes se você não tem célula a versão binária, eles são como problemas com a instalação. Então apenas sempre instalou uma versão binária, mas isso é apenas basicamente vai nos fornecer com o driver que SQLAlchemy pode usar para realmente se conectar ao banco de dados. Então, sim, como podemos configurar essa conexão de banco de dados enquanto fazemos isso? Então já podemos ver aqui que eu já o importei. Mas vamos usar este método de criação do mecanismo. E vamos criar um motor. E o motor vai permitir-nos interagir com o nosso banco de dados. Então, primeiro, precisamos obter todos os parâmetros do nosso banco de dados. Seremos apenas o nosso nome de utilizador Postgres. E uma boa maneira de fazer isso é definir isso como uma variável de ambiente. Postgres. Usuário. Então vamos pegar a senha Postgres, que também precisamos da senha Postgres. E então também vamos precisar do host ou do URL ou onde quer que ele esteja localizado. Então vai ser o anfitrião Postgres. E então também precisaremos obter o banco de dados que precisamos nos conectar no servidor Postgres. Então estes são os detalhes de conexão que precisamos. E a partir disso podemos então criar uma cadeia de conexão que nos permitirá conectar ao banco de dados. Então a outra coisa que eu fiz aqui é que eu usei o pacote do sistema operacional, que na verdade é importante para mim só porque é muito bom. Mas isso só me permite acessar coisas do nosso sistema operacional especificamente aqui entrando no ponto Environ e me permite acessar variáveis de ambiente que eu possa obter. Por exemplo, aqui, eu vou usar o ponto GetMethod. Agora, se você não viu isso antes com o método dot get, é se nós criar como um dicionário, por exemplo, e nós apenas criar uma variável aqui. Se você fizer x dot get, infelizmente significa, Vamos renomear esse x-dot novamente. A vai obter o valor deste dicionário. Por exemplo, se você fizer x-dot Gatsby, que não está incluído no dicionário, é apenas meio que não nos dar nenhum. Assim, desta forma, em vez de fazer isso, que pode falhar se estamos acessando valores que estão incluídos, o GetMethod nos dá o valor reverte nenhum para que ele não falhe. E então o que podemos realmente fazer é que podemos usar um ou aqui, o que acontece é, por exemplo, se você fizer em estoque obter B ou então podemos fornecer como um valor padrão que queremos usar. A deve ser uma string e inteiro, inteiro ou qualquer outra coisa. Então, podemos ver se o valor não existe, obtemos o valor padrão. E se ele existe, então obtemos o valor do GetMethod aqui. Então nós vamos dizer recebendo nosso usuário Postgres, ou ele vai ser apenas vazio. Ou vai ficar vazio. Ou é apenas apontar para o seu anfitrião local, ou vai ser Postgres. Agora, se você tiver postgres rodando em um Mac e o instalou, então é muito provável que seu Postgres local não tenha nome de usuário ou senha. Mas se você estiver executando no Windows, é muito provável que você tenha um nome de usuário e senha. O nome de usuário provavelmente será Postgres, mas a senha será o que você definir sua instalação. Então lembre-se se você está no Windows, isso é muito provável que seja repentino ou Alice vai reclamar que ele pode se conectar porque a senha não é nenhuma ou não conseguiu autenticar ou o que quer que seja. Mas em um Mac, você não precisará definir um nome de usuário e senha porque provavelmente não o definiu menos que tenha definido explicitamente para seu banco de dados. Então, novamente, o que estamos fazendo aqui é ou estamos tentando obter esses valores de nossas variáveis de ambiente ou se eles não estão disponíveis, selecionamos valores padrão. E isso é realmente muito bom porque então nós podemos configurar diferentes ambientes, variáveis de ambiente para diferentes ambientes. Por exemplo, você pode ter um ambiente de teste, ambiente de produção ou um ambiente de teste local. Se você não definir nada, então nós apenas levamos nossos ambientes de teste locais. Caso contrário, tomará quaisquer variáveis que definimos. Então agora que temos um ambiente difícil variáveis aqui, podemos criar nosso mecanismo que vai nos permitir conectar a um banco de dados. Nós vamos usar o método do motor de caixa que temos de SQLAlchemy. E nós vamos apenas usar cordas f para isso. Então, a primeira parte, vai apenas indicar que esta é uma conexão Postgres. Vamos fazer PostgresSQL, ponto-e-vírgula barra barra. E então vamos ter nosso usuário o. Vamos, vamos reutilizar ou ponto e vírgula, desculpe, dois-pontos, a senha no endereço do host, como eles chamam isso? Sim, Apigee. O endereço do host ou o endereço IP ou qualquer outra coisa, barra, o banco de dados. Então esta é a nossa cadeia de conexão aqui, nome de usuário, senha, host, endereço e o banco de dados ao qual estamos nos conectando. Muito bem, agora temos a configuração do motor aqui. Temos nossa consulta SQL que criamos aqui. A coisa boa sobre o mecanismo é que ele nos fornece um meio para criar conexões de banco de dados. Mas até inicializarmos uma conexão de banco de dados, não há nenhuma conexão sendo criada. É apenas, bem, é basicamente apenas uma classe que nos permite criar essa conexão uma vez que explicitamente dizemos para fazê-lo. Então agora vamos em frente e executar esta consulta. Vamos dizer largura. E, em seguida, usando nosso motor, nós vamos nos conectar. Agora existem diferentes métodos que podemos usar aqui. Um deles é ponto connect, que apenas cria uma conexão. Também podemos fazer não começar, o que cria uma conexão e inicia uma transação. Mas nós realmente não precisamos usar transações aqui. Então, vamos apenas criar uma conexão. E nós vamos ter isso em nossa variável con aqui. E você vai notar são todos lembrar a sintaxe de também como abrir arquivos de nome de arquivo aberto e, em seguida, como lê-lo como um all in file, esta é exatamente a mesma sintaxe que temos aqui onde abrimos um arquivo, então podemos fazer algo com um arquivo. E uma vez que sair desta instrução width, o arquivo também está perto para nós. Então temos esse Gerenciador de Contexto aqui, o que é muito bom porque criamos a conexão com ele. Podemos acessar a conexão usando essas variáveis de coluna quando eu chamo. E uma vez que saímos deste bloco de largura, a conexão é automaticamente fechada para nós, então nem precisamos nos preocupar com isso. Então agora podemos usar nossa conexão. E com a nossa instância de conexão aqui, podemos ter este método não executar, que vai nos permitir executar esta instrução SQL aqui. Agora há mais uma coisa que precisamos fazer, que é precisamos fornecer essa entrada, já que não fornecemos aqui como cordas f. Então precisamos fornecê-lo quando estamos fazendo a inserção. Agora, para fornecer formatação para esta sintaxe, nós realmente precisamos importar alum, uma classe especial que nos permitirá fazer isso a partir de SQLAlchemy dot SQL. Vamos importar texto. E então vamos embrulhar isso no texto aqui. E então nós vamos fornecer nossa contribuição aqui. Então nós vamos ter o nosso símbolo, que é este símbolo de dois pontos, ou símbolo, vai ser o símbolo aqui. O preço vai ser o preço. E o extrato de uma vez. Vai ser o tempo extraído aqui. Tudo bem, então vamos repassar isso mais uma vez. Então nós temos o nosso trabalhador Postgres, que leva no símbolo, o preço, bem como o tempo extraído como variáveis de entrada. E, em seguida, ele também cria um, uma instância para uma conexão de banco de dados com o endereço de conexão postgres. E então nós estamos realmente indo para chamar, é nós vamos chamar inserir dois banco de dados. E ele vai criar a consulta SQL para nós. Então vamos nos conectar ao banco de dados. Então vamos criar uma conexão com o banco de dados. E com essa conexão, vamos executar a instrução SQL que criamos aqui. Vamos usar esta formatação de texto aqui porque temos este formato especial que basicamente nos permite alguma proteção contra como imposto de injeção. Então apenas que a formatação é adequada. E então nós podemos realmente fornecer a formatação aqui como apenas uma segunda variável de entrada e alguns dicionário muito simples. E então ele vai preencher os valores para nós. E, em seguida, uma vez que sair desta instrução width, A conexão também vai ser fechada automaticamente para nós, porque estamos usando isso com declaração aqui. Então, um muito conveniente, tudo bem, então vamos voltar para o nosso programador mestre. E o que temos que fazer aqui é uma vez que obtemos um valor de nossa fila de entrada, aqui, vamos criar uma instância de nosso trabalhador Postgres, certificando-se de fornecer o símbolo, o preço, bem como a extração de um tempo. E então nós, nós vamos obter isso de, bem, e vamos apenas supor que é isso que vamos obter com o nosso valor de entrada aqui. Então nosso valor de entrada aqui que ou vai ser uma lista que se parece com isso, ou vai ser uma tupla que se parece com isso. De qualquer forma, porque temos controle total sobre isso, vamos assumir que será assim que obtivemos nossos dados. Claro, você sabe, podemos tornar isso mais geral e fazer isso ser como um dicionário. E então poderíamos dizer símbolo é igual à válvula, novamente símbolo e fazer a mesma coisa para preço igual Val ponto get, Prius e assim por diante. Torna-o um pouco menos propenso a erros. Mas, você sabe, esse não é o propósito disso agora. Nós só, você sabe, nós só queremos fazer isso funcionar. Então, vamos nos certificar, por enquanto, de que é assim que vai funcionar. E então uma vez que temos nossa instância profissional assistente social Aqui, vamos chamar inserir no banco de dados. Muito bem, isto é criar o nosso trabalhador Postgres. Agora vamos continuar isso na próxima lição porque também precisamos fornecer a fila de entrada aqui. Precisamos enviar esses valores para lá. E também, precisamos incluir isso em nossa função principal aqui, porque isso já está ficando muito longo. Vamos em frente e parar aqui por agora e depois continuar isso na próxima lição. 9. Integrando o trabalhador de Postgres: Tudo bem, agora que montamos nossa garota do Porto Postgres, vamos continuar com isso. Integre isso em nossa função principal, e faça algumas outras mudanças na linha para garantir que tudo esteja funcionando corretamente. Então, primeiro de tudo, em ordem, função principal, vamos importar o agendador mestre Postgres. E nós vamos fazer uma coisa semelhante como fizemos para o trabalhador Yahoo Finanças aqui. Isto e isto é, em vez de finanças, vão ser os nossos pós-graduados. E vamos mudar a entrada em cubos e um segundo. E apenas atualizando os nomes aqui. Lá vamos nós. E NAM, trabalhador pós-graduado, assim e a fila de entrada. Então agora eu preciso de um novo Q. E isso vai ser uma deixa VIP Postgres como esta. Tudo bem, então nós temos um programador Postgres threads aqui, número de podcasts trabalhadores, suponha que dois. Por enquanto, vamos ver como as coisas estão indo. Postgres scheduler, que vai ser instância up para Postgres master scheduler, que vai ter esta fila de entrada aqui. E você está acompanhando essas ameaças. Tudo bem, então agora que temos esse Postgres Q, nós realmente precisamos colocar valores nele. E então nós vamos ter isso ser uma fila de saída. Top vamos fornecer a um agendador de preços do Yahoo Finance. Há duas maneiras de resolvermos isso. O primeiro é claro que podemos explicitamente torná-lo um argumento de entrada. Ou podemos realmente usar nossos argumentos de palavra-chave aqui. E então nós vamos dizer, ok, então nós temos em nossa saída OOP, ou saída Q, vai ser? E, em seguida, a partir de nossos argumentos de palavra-chave, nós vamos obter a saída Q. E se isso não existir, isso vai ser nenhum. Caso contrário. Sim, vamos conseguir valores daqui. Certo, então durante o método de execução, temos o preço aqui. E então podemos dizer, se a saída Q não é , então em nossa saída Q, vamos colocar esse preço. Da mesma forma. Assim que terminarmos aqui, vamos em frente e certificar-nos de que também enviamos para os nossos marcadores a jusante. Tudo bem, então o que acabamos de fazer? Bem, nós adicionamos uma fila de saída. E a razão pela qual precisamos de uma saída Q é porque agora temos um processo de três etapas. O primeiro passo é obter todos os símbolos, que estamos fazendo com o nosso wiki worker, que não é um tópico. É apenas, bem, é parte do termo principal, mas é apenas um trabalhador que recebe todos os símbolos que o coloca no símbolo Q. O símbolo Q é então lido pelo agendador de preços Yahoo Finance, o programador mestre aqui. E toda vez que ele recebe o valor, ele vai processá-lo e obter o preço. Agora, em vez de imprimir o preço, vai enviá-lo para a saída Q aqui. E a saída Q é o que nosso programador mestre Postgres aqui vai estar consumindo como sua fila de entrada, como podemos ver aqui. E vamos dar uma olhada nisso. E uma vez que terminamos, uma vez que saímos, queremos ter certeza de que também colocamos na saída Q e terminamos. Então o que os trabalhadores a jusante também são, você sabe, recebendo essa mensagem feita passada para eles. Agora, uma coisa importante a ser ciente é o formato que estamos esperando aqui. Aqui, como esperamos o símbolo, o preço, bem como o extraído para o tempo. Então vamos realmente definir aqueles para ser os valores de saída de saída. Então você precisa fornecer o símbolo aqui, que vai ser o valor que obtemos a partir daqui, o preço, bem como o tempo extraído, que vamos apenas converter isso em um inteiro. E isso é o que vamos colocar em sua saída Q. Uma vez que novamente, nosso trabalhador Postgres está esperando o símbolo e, em seguida, o preço e, em seguida, o símbolo de tempo extraído, porque eles estão obtendo isso da fila de entrada, que tem o símbolo Q. Preço. E então o tempo extraído bem aqui. E esses valores que vamos colocar em nossa saída Q. E então vamos lê-los aqui como nossa fila de entrada em nosso trabalhador Postgres. Tudo bem, então, sim, e então nós vamos enviar o valor w1, que nós podemos obter aqui. Tudo bem, então vamos em frente e, vamos em frente e testar isso. Veja como as coisas estão correndo se há algo que perdemos. Tenho uma saída inesperada de argumento de palavra-chave Q. Então, na verdade, neste caso, devemos explicitamente defini-lo porque estamos passando como argumentos de saída. E assim está nos dando onde estamos passando nossos argumentos de palavra-chave. E está basicamente dizendo, oh, bem, ok. A classe de threading que usa esses argumentos de palavra-chave, não, você sabe, não sabe o que, como lidar com filas de saída. Então, na verdade, vamos defini-la explicitamente para que não passemos porque está causando erros a jusante. Como este. Vamos fazer isso mais uma vez. Veja como as coisas estão indo agora. Tudo bem, Ok, então parece que as coisas estão correndo e nós estamos recebendo os valores transmitidos. Bud, estamos tendo alguns problemas para inserir os dados em nosso banco de dados. Tudo bem? E a questão principal parece estar aqui com o nosso carimbo de data/hora. E este caso é realmente apenas reclamando que estamos fornecendo um número inteiro aqui, mas ele está esperando um carimbo de data/hora. Então vamos em frente e incluir um elenco aqui. Vamos colocar isso em uma nova linha apenas para facilitar a formatação. Então vamos lançar este valor como um carimbo de data/hora. Vamos fazer listas de elenco aqui. Vamos tentar isso mais uma vez. Ainda estou tendo problemas. E vamos ver que valor estamos passando aqui. Claro, estamos usando o. Então vamos começar enviando o valor de tempo. Oops, queremos enviar basicamente como uma instância datetime que podemos inserir. Então, assim. E não espero que precisemos mais disso. E vamos apenas ir em frente e certifique-se de lançar isso como uma string para que possamos obter o formato string. De modo que o valor que vamos obter aqui vai ser assim, algo assim, o que for. Estou só a inventar um tempo, como algo como este formato. Tudo bem, então nós vamos conseguir isso usando a classe Datetime aqui. Então vamos passar em um objeto datetime, que vai ser UTC. Agora, quando você usa UTC agora em vez de agora, apenas para que tudo seja padronizado e nós ainda precisamos da biblioteca de tempo para, para dormir aqui no final. Certo, vamos tentar mais uma vez. Parece estar em execução e nós realmente não temos nenhuma saída de impressão, mas vamos em frente e verificar nosso banco de dados. Puxando uma mesa aqui. Oh, lá vamos nós. Portanto, nossos valores estão sendo inseridos para nós, como podemos ver, o que é realmente ótimo. Então é exatamente isso que estamos esperando. E sim, então basicamente vamos recapitular rapidamente o que está acontecendo agora porque temos muitas peças diferentes em movimento. Então, a primeira coisa que temos o nosso fio principal aqui. Em nosso tópico principal, onde, em seguida, criar um símbolo Q, bem como um Postgres q. Estas são dicas onde vamos passar sobre os símbolos que obtemos do nosso depurador wiki. Então, apenas olhando para a página wiki aqui, isso está passando por todos os símbolos aqui. Todos os símbolos aqui, e está passando estes para este símbolo de saída Q aqui. E então nosso agendador de preços do Yahoo Finance, que temos quatro instâncias de atualmente, estará lendo a partir dessa fila. E então ele vai obter o preço ou ele vai tentar, e ele vai passá-lo para a ponta Q a jusante para fazer. E vai passá-lo para o Q a jusante, que vai ser o nosso Postgres Q aqui. E isso vai levar esses valores. Ele vai ler do Postgres Q, que é a saída Q aqui. E o nosso trabalhador Postgres vai continuar a ler a partir desta fila. E cada vez que ele recebe um valor, é, sim, eu vou inseri-lo no banco de dados e nós vamos obter o valor w1. Então ele vai sair do loop aqui. E nós estamos nos certificando de apenas, se nós obtivermos o valor w1 em nossa entrada aqui, nós estamos certificando-se de passar isso para a saída Q, que é postgres vai estar lendo de Sloan. Sim, isso é o que temos acontecendo. Vamos ver quantos registros temos em nosso banco de dados agora. Um 180. Então estamos esperando. 550. E mais uma vez, isto está a correr bastante devagar, principalmente porque temos esta coisa de dormir a acontecer aqui para limitar o quão rápido estão a ir. Porque, é claro, isso pode estar correndo muito mais rápido. Então, apenas para ter certeza de que isso está terminando corretamente, em vez de obter todos os símbolos. Vou ter um símbolo ou não. Sim, teremos um contador de símbolos. E cada vez que inserirmos um símbolo, vamos aumentar isso em um. E então digamos apenas para ter certeza que isso está funcionando corretamente. Se, oh, on, se nós tivermos pelo menos cinco símbolos, nós vamos sair disso só para ter certeza de que nós não temos esperar todo o caminho até chegar como 550 aqui, só para ver se isso está funcionando corretamente. Então nós vamos sair dessa, reexecutar isso. E agora deve estar indo muito mais rápido. Deveríamos estar indo cinco símbolos que devem ser inseridos no banco de dados. E então tudo deve sair, o que acontece. Ótima. Então isso é importante para nós porque se não estivesse saindo, isso significa que nossos fios estão pendurados em algum lugar, que ainda há um fio ativo em algum lugar. E podemos ver que é o que conseguiríamos. Se não fizéssemos isso. Então nossos trabalhadores Postgres nunca seriam informados, você sabe, feito e eles simplesmente continuariam. Na verdade, parece que não vamos nos juntar, que é o que vemos aqui. Mas, você sabe, nós não estamos saindo porque nossos Postgres, trabalhadores estão presos neste loop basicamente sendo bloqueados por isso. Eles estão esperando para obter o próximo valor, mas a fila está vazia e nada está sendo colocado na fila. Então, fique preso aqui para sempre, então não vai parar. Então é por isso que é importante que passemos esses valores para garantir que as pistas a jusante também estejam cientes de que, ok, é hora de parar. Então, saindo disso, há mais uma coisa que podemos realmente fazer para ajudar a evitar isso. Então, na verdade, vamos deixar isso comentado por agora e ir para o nosso trabalhador Postgres. E aqui vamos adicionar um tempo limite. E vamos colocar isso em 10 segundos. E nós vamos dizer, tudo bem, se nós não tivermos um valor em 10 segundos, então nós queremos sair. Então, vamos adicionar uma declaração try and except aqui e obter a exceção vazia especial, que podemos obter a partir de Q. Importar fila vazia é novamente uma biblioteca Python padrão. Então podemos importar a partir daqui. E o multiprocessamento Q, que é o que importamos aqui, na verdade apenas implementa diretamente a classe de fila da biblioteca Python da fila Standard. Então, a partir daqui podemos obter a exceção vazia. Então, se nós pegar especificamente a exceção vazia, então nós só queremos imprimir Q ou timeout violado e Postgres, agendador parar. E também aqui também, queremos sair. Então, neste caso, nós não estamos, nós não estamos enviando o sinal feito para um trabalhador Postgres. E assim vai ser pendurado um pouco. E, mas isso vai ter um tempo limite aqui. E nós realmente vamos ver em apenas um pouco que os trabalhadores Postgres vão parar de qualquer maneira porque não há nada na fila e chegou aos tempos limite. Então podemos ver aqui o primeiro segmento de parada, parar. Lá vamos nós. Então é por isso que é legal porque, você sabe, ele meio que se protege de esperar para sempre. Mas é claro, precisa estar ciente de porque se você teve um tempo fora no tempo limite não é grande o suficiente para os valores para entrar a partir do topo. Vocês são trabalhadores a jusante, na verdade, vão desistir antes de terem a chance de trabalhar. Ou se houver alguma interrupção no meio, então, você sabe, seus trabalhadores a jusante vão parar enquanto as coisas ainda estão acontecendo. Então você precisa ter um pouco de cuidado com isso. Você sabe que você não define seu tempo para ser muito curto porque, claro, é porque isso pode causar problemas. E assim, você sabe, você quer ter certeza de que você idealmente sempre termina enviando algum tipo de comando de saída. Vamos ver o seu QRS agora. Está na hora de parar aqui. E é claro que temos o tempo limite aqui e podemos fazer a mesma coisa para o nosso Yahoo Finance vai aqui. Vamos dizer, tente obter um valor. Recebemos a exceção vazia. Vamos imprimir o Yahoo. Agendador. A fila está vazia. E depois vamos dizer que vamos parar, vamos fugir. E vamos dizer para Q e porta vazia. Isso, só vai reorganizar as importações aqui um pouco. Que todas as bibliotecas padrão estão no topo aqui. E todas as bibliotecas instaladas estão na parte inferior. Normalmente. Lá vamos nós. Apenas fornece uma estrutura um pouco mais fácil que sabemos que estes são todos os padrões e estes que tivemos que instalar. Ok, então e tudo que nós também adicionamos saída realmente não definir um tempo limite aqui. Então, nós também estamos definindo um tempo limite aqui apenas por precaução. Mas é claro, você sabe, ter cuidado com isso porque você pode ter seus trabalhadores sair enquanto eles realmente deveriam estar trabalhando porque há algum tipo de atraso acontecendo a montante. E nós realmente não precisamos de nenhum argumento de palavra-chave aqui. Então nós podemos apenas tirar estes para imprimir declaração aqui também. Tudo bem, sim, então agora temos nossos trabalhadores configurados para um deles, tipo de obter os símbolos daqui. Para cada símbolo que obtemos, passamos para obter os dados do Yahoo Finance. E por cada preço que obtemos, colocamos isso em um q jusante, que são os trabalhadores Postgres, então, vão consumir. Agora apenas algumas pequenas coisas para fazer, que vai ser apenas fazer a junção no final aqui. Então vamos rever Postgres, ameaças do programador, e apenas ligar para junções no final aqui. E eu estou realmente indo para mudar a lógica do nosso QS de saída aqui um pouco, porque é possível que, você sabe, agora nós estamos assumindo que temos uma saída Q, mas talvez nós queremos ter mais de um Q. Então, para acomodar isso, vou ler isso em uma variável temporária. Eu vou dizer que se nosso Q temporário não é muita lista, então eu só quero que isso seja uma lista. Então agora nosso QS de saída vai ser uma lista que pode ser um, eles podem ser vários. E então temos que, claro, mudar isso um pouco. E porque não vamos mais ter nenhum aqui. Então o que podemos fazer é dizer para a saída Q nas filas de saída. E, em seguida, para cada saída Q, vamos enviar em feito. E se não há elementos aqui, então isso vai ficar vazio. Então não há filas de saída, então isso vai ficar vazio. Caso contrário, você sabe, se nós temos um, então nós vamos ter um. E se tivermos mais de um, então teremos mais de um. E podemos, na verdade, sim. Tudo bem. Então, sim, então agora nós apenas tornamos isso um pouco mais agradável porque nós podemos fornecer isso como uma lista de entrada. E vamos realmente fazer isso também, mesmo que aceitemos apenas a variável específica. Mas isso fornece isso como uma entrada, como uma lista. Então, podemos ter um Q a jusante? Vamos fazer isso mais uma vez para ter certeza de que está funcionando. Mas, desta forma, agora temos um pouco mais de flexibilidade, porque talvez ela tenha esquecido de mudá-lo aqui. Oh, lá vamos nós. Quatro, saída Q e QS de saída. Lá vamos nós. Certo, então agora temos um pouco mais de flexibilidade porque talvez não queiramos apenas salvar isso em um banco de dados, mas talvez queiramos salvar isso em vários bancos de dados. Então o que podemos fazer é que podemos ter o nosso principal trabalhador do Yahoo Finance aqui, em vez de apenas ter uma saída Q. Ele pode ter várias filas de saída e diferentes trabalhadores a jusante. Então podemos dizer que temos um trabalhador Postgres. Nós também pode ter como eu li US worker ou MySQL worker ou qualquer outro banco de dados que você tem. Cada um deles pode estar consumindo das diferentes dicas que fornecemos aqui. E nosso trabalhador do Yahoo Finance estará apenas escrevendo para cada saída Q. Então, cada saída Q que temos, vamos escrever esses valores também. E então os trabalhadores a jusante podem, você sabe, usar todas essas coisas e nós basicamente obtemos os preços, mas podemos reutilizá-lo em meio que colocá-lo diferentes pistas para que os diferentes trabalhadores possam consumir deles. E isso nos dá mais flexibilidade porque, você sabe, nem sempre vai ser um dentro, um fora. Às vezes não vai haver saída. Às vezes, haverá várias saídas. E isso nos dá um pouco mais de flexibilidade nesse sentido. 10. Introdução ao arquivo em Yaml: Tudo bem, então agora que temos este programa de trabalho implementado, vamos em frente e limpá-lo um pouco. Torná-lo um pouco mais agradável ter uma visão geral, bem como ser capaz de expandi-lo mais tarde se quisermos, sem realmente apenas ter que adicionar novos trechos de código ou copiar colar ou alterar a lógica lá dentro. Então, em vez disso, o que vamos fazer, e vamos realmente definir isso em algum tipo de arquivo onde podemos dizer especificamente que estas são as pistas que temos, ou os trabalhadores que temos. E isso vai definir nosso programa aqui. E então o que vamos fazer é escrever um arquivo YAML. E é isso que vamos abordar nesta lição, escrever o arquivo, bem como como como podemos lê-lo e realmente o que ele significa para nós. Então, para fazer isso, vamos começar e criar um novo diretório aqui. E eu vou chamar isso de Pipelines. Pode chamá-lo do que quiser. Vou chamar pipelines porque o que temos aqui meio que no pipeline, começamos descrevendo os dados brutos do site da Wikipédia, passando-os para eles, passando-os para eles, sendo extraídos do sinal do Yahoo, e depois passando-os para ser carregado no Postgres. Então isso vai ser um oleoduto para nós aqui. E então aqui eu vou criar um novo arquivo. E isso vai ser o nosso wiki, Yahoo, sucata ou pipeline, e chamá-lo de ponto YAML. Por que ML? Agora para ser capaz de ler este arquivo em Python, e nós vamos apenas fazer esse tipo de um pouco de cada vez. Nós também vamos ativar meu ambiente virtual aqui. Mas eu vou para PIP e tropeçar. Pi YAML. Carregue em Enter aqui e deixe instalar isso. E isso é meio que agora e a biblioteca que precisávamos para ser capazes de ler isso. E então, em um segundo, quando escrevemos este arquivo YAML, podemos usar a biblioteca de pizza, que então apenas converterá isso em uma basicamente como uma espécie de lista aninhada ou estrutura de dicionário para nós que veremos em um segundo. Então a primeira coisa que queremos, se olharmos para o nosso programa principal aqui, é se temos filas. Então, de alguma forma, precisamos definir as pistas que queremos. E então também temos trabalhadores. São como as essências do que queremos. Então eu vou definir aqui, e eu vou apenas dizer, tudo bem, estas são as pistas que queremos. E eu vou escrever isso um pouco e em um segundo, vamos lê-lo e, você sabe, podemos explorar um pouco como esse arquivo YAML realmente se transforma em uma estrutura de dados Python. Então aqui, eu vou apenas listar as pistas. O primeiro, vou dar um nome a ele. E isso aqui vai ser, se voltarmos para a nossa função principal aqui, vai ser o símbolo Q. Então eu vou chamar esse símbolo Q, chamá-lo do que você quiser. E eu também vou dar uma descrição. Novamente, não se preocupe com isso agora. Eu meio que recuperarei isso em um segundo. Eu só quero ter algo aqui para que possamos olhar para ele. E este vai ser o contém símbolos para ser eliminado do Yahoo Finanças. E então nós queremos ter outro Q, que vai ser nosso Postgres upload. E a descrição aqui vai ser contém dados que precisam ser carregados. Postgres. E então também temos trabalhadores. E os trabalhadores. O primeiro aqui, se olharmos para isto, vai ser o nosso trabalhador wiki ou podemos, sim, ok, trabalhador está bem. Aqui podemos dar uma descrição. Isto retira a página bruta da Wikipédia e retira símbolos. E então, novamente, vamos tipo de repassar isso iterativamente. Mas eu queria ter o tipo de base como a localização ou podemos encontrar este trabalhador. Então ele vai ser em trabalhadores ponto chave trabalhador. E a classe que queremos usar será essa classe de trabalho wiki que vou colocar aqui. E então nós também queríamos encontrar filas de entrada, etc, que, que nós vamos chegar em um pouco. Mas vamos deixar assim. Então agora temos algo para realmente olhar. E então vamos em frente e carregar isso e ver como esses arquivos YAML realmente se traduz para algo utilizável em Python. Então eu vou apenas lançar Python sobre o meu terminal aqui. E eu vou importar YAML, o que podemos fazer agora porque instalamos o PMO anteriormente. Agora o que eu vou fazer é dizer com aberto. Linhas de tubos. E eu vou apenas copiar este nome aqui porque eu provavelmente vou soletrar errado. E então teremos que encontrar o erro de digitação. Vou abri-lo no modo de leitura. Eu vou dizer, chame isso de nosso arquivo. E novamente, vamos repassar isso e então vamos tipo de recapitular tudo o que fizemos. Vamos fazer um pouco de exploração, mas precisamos ter algum tipo de base primeiro. E assim nossos dados YAML será apenas, e então vamos usar nossa biblioteca YAML. Vamos fazer uma carga segura. E nós vamos colocar um “A “aqui, nosso arquivo de arte que nós lemos em “Enter”. Tudo bem, então nós carregamos. Então vamos em frente e dar uma olhada nisso. Então podemos ver é nossos dados YAML é realmente, e se olharmos para o seu tipo, é um dicionário. Então a primeira chave que temos são as chaves que temos. Se olharmos para as chaves, é que temos duas chaves, pistas e trabalhadores, e isso é exatamente o que temos aqui. A primeira coisa é um q, e a segunda coisa é um trabalhador. E você pode quase agora ver o que temos em Python, você pode reconhecer a estrutura aqui, certo? Então temos basicamente esse tipo de formato de dicionário familiar onde temos o nome e, em seguida, o ponto-e-vírgula, e então temos os valores contidos dentro. Agora o que podemos ver aqui está dentro de pistas, nós realmente temos uma lista. Então vamos em frente e pegar nossos dados YAML. Vamos procurar filas. Então aqui temos uma lista. E a razão pela qual temos uma lista é porque na verdade usamos esses traços que indicam elementos da lista. Então, neste caso, temos que listar elementos aqui. Mas se olharmos para dentro, digamos que o primeiro elemento lista verá novamente aqui temos um dicionário como fazemos aqui. Então podemos ver que temos como uma forma de repetição fora do primeiro estamos definindo tipo de chaves de dicionário. Então dentro estamos definindo o conteúdo. E então dentro, neste caso, estamos usando elementos de lista indicados por um traço. E então aqui dentro nós novamente temos um dicionário que podemos ver aqui. Temos o nome, que é o nome aqui, e temos a descrição. Agora, quando estou escrevendo isso, você deve ter pensado, Oh, você está usando palavras-chave específicas para tipo de indicar todas essas coisas. Eu não sei. Eu só decidi usar a descrição do nome, classe de localização porque eles são convenientes e eles são claros para o programador quando você está lendo isso, eles são muito descritivos e claros, mas você sabe, realmente não se importa o que usaria. Nós poderíamos realmente usar qualquer coisa aqui porque novamente, nós estamos apenas recebendo dicionários e listas daqui que podemos usar. Mas só para tornar nossas vidas mais fáceis, seja quando escrevemos agora ou quando voltamos a ela, quando queremos mostrá-la a outras pessoas, queremos ter certeza de que usamos nomes descritivos para que, você sabe, seja gentil de claro o que está acontecendo. Então algo que também podemos fazer na verdade, que pode ajudar a limpar um pouco a sintaxe. Em vez de usar esta sintaxe aqui em baixo, podemos realmente usar uma sintaxe como esta e o resultado, mas nós vamos começar vai ser o mesmo. Então vamos voltar aqui e vamos recarregar nossos dados. E então vamos dar uma olhada em nossos dados YAML novamente. E podemos ver aqui os valores que temos aqui são, observe que eu tenho um erro de digitação e uma descrição aqui. Mas podemos ver que os valores que temos aqui ainda são os mesmos, certo? Nada é alterado para exatamente o mesmo formato está aqui. Agora esta é apenas uma maneira diferente de representá-la. Então, se você quiser, este tipo de quase trazê-lo de volta exatamente para a estrutura Python que nós temos que tipo de acostumado em Python, exceto é claro que usamos aspas desde que nós estamos realmente definindo um dicionário e caso contrário nós estaria fazendo referência a nomes de variáveis. Mas uma vez que você se acostumar, este formato pode realmente ser um pouco mais limpo de ler do que este. Então é por isso que vou desfazer essas mudanças. E eu vou ter isso do jeito que era antes porque fica um pouco mais limpo de ler. Mas a outra maneira é apenas mostrar a você, novamente, talvez traduzi-lo de volta para coisas como, você sabe, em Python para que você possa entender melhor o que exatamente está acontecendo. Mas nós podemos ver aqui, ok, então nós definimos as pistas e novamente, nós as chamamos de dicas porque é conveniente para nós, não porque é necessário nele de qualquer outra maneira. E temos esses trabalhadores aqui de novo porque é conveniente para nós. Então temos o nosso trabalhador wiki. E novamente, aqui esses nomes não precisam ser os mesmos. É apenas, você sabe, meio conveniente e descritivo de usar, mas podemos chamar isso de algo completamente diferente. Este ano é importante porque vamos usar isso mais tarde, não agora, mas mais tarde. Vamos usá-lo para realmente carregar e inicializar dinamicamente esta classe a partir deste local. Portanto, queremos ter certeza de que este caminho de localização e também poderia chamá-lo um caminho baseado em caminho, o que está correto. E então aqui nós queremos ter certeza de que estamos referindo o marcador correto como este para que possamos realmente inicializá-lo. Então, temos o único trabalhador aqui. Eu também quero colocar filas de entrada. Agora, neste caso, nós realmente não temos uma fila de entrada. Então eu não vou defini-lo. Mas talvez queiramos passar como valores de entrada. E estes podem ser apenas uma lista de URLs para limpar, por exemplo. Então, algo que podemos fazer é pegar esse URL aqui que queremos suprimir e em vez de codificá-lo em nosso wiki worker, podemos realmente defini-lo aqui. E então se tivermos outros sites wiki que seguem a mesma estrutura que realmente nos permitem reutilizar ou trabalhar, ou expandir ou trabalhar para tipo de ser capaz de aceitar esses diferentes sites. Podemos colocar mais URLs aqui quando chegarmos a esse ponto. Ou, você sabe, se você tiver dados como esse. Mas agora nós vamos ficar com isso, mas, você sabe, torná-lo um pouco mais geral para que nós estamos definindo tudo por aqui. Então temos o nosso primeiro trabalhador. Então vamos criar nosso segundo trabalhador, que se olharmos para trás para nossa função principal aqui, teremos nosso trabalhador do Yahoo Finance. Então este aqui vai ser o nosso trabalhador do Yahoo Finance. A descrição aqui vai ser puxa dados ou puxa dados preço para um símbolo de ações específico do Yahoo Finanças. Localização aqui vai ser trabalhadores ponto, e eu vou apenas copiar este nome aqui para que não haja erros de digitação porque isso vai ser frustrante. E a classe que queremos carregar aqui será nosso jovem agendador de preços do Yahoo Finance, não os trabalhadores de preços serão os mesmos que estamos usando aqui. Então é isso que queremos usar. E aqui nós vamos ter uma fila de entrada terá apenas este ser uma entrada singular q. e isso vai ser realmente nós podemos apenas manter isso diretamente como um dicionário em vez disso. Então nossa entrada q aqui vai ser, bem, a saída daqui. Então vamos em frente e definir QS de saída. Este aqui, vamos ter um plural no caso de você querer enviá-lo para várias pistas. Mas, por enquanto, vamos enviá-lo para o símbolo Q que definimos aqui. Tudo bem? E novamente, estamos apenas referindo os nomes aqui porque estes são apenas filas gerais. E assim podemos fazer referência a essas diferentes pistas. Estes são, vamos ver mais tarde sobre como vamos usá-los. Mas sim, isso, ter essas convenções de nomenclatura, especialmente para o Q meio que apenas nos permite nomear corretamente e uma referência tudo. Então nossa entrada q aqui vai ser nosso símbolo Q. E nossa saída QS aqui vai ser apenas nosso Postgres upload Q. Agora, a razão pela qual eu quero ter vários QS saída é talvez eu não quero apenas enviar esta informação para um em um tipo de trabalhador a jusante, mas na verdade vários. Então, talvez eu queira que meu trabalhador wiki envie para o trabalhador do Yahoo Finance para obter os dados de preço para fora, mas também quero enviá-lo para um trabalhador diferente, que apenas armazenar diretamente todos esses dados brutos em algum lugar e não faz mais nada com ele. Ou talvez faça algo completamente diferente com ele. Assim eu posso enviá-lo para vários locais e diferentes trabalhadores a jusante podem ver que estão lendo a partir daqui. Sua jusante pode usar essas informações de maneiras diferentes. Certo? Vamos definir o nosso último trabalhador. Se voltarmos à nossa função principal, será o nosso anfitrião Chris. Então esse aqui. Então aqui vamos chamar isso de nossa descrição do trabalhador Postgres. Faça estoque de dados e salve em Postgres. A localização vai ser comer. Trabalhadores, ponto postgres trabalhadores. E a classe que vamos usar será novamente o programador mestre. Já que esse vai ser o que vai ler da fila e tudo mais. Assim como estamos fazendo em nossa principal função aqui. Está bem? A fila de entrada. Vai haver postgres carregando. E nós realmente nem vamos definir uma fila de saída porque há, você não quer mais enviar esses dados. Certo, então essas são as nossas definições básicas. Agora podemos atualizar este arquivo YAML mais tarde ou podemos mudar um pouco enquanto estamos indo. Nós realmente notamos que talvez você queira descrever as coisas um pouco diferente. Mas por enquanto, esta é uma espécie de descrição básica de um programa, é claro, agora não faz nada porque nós realmente temos que fazer uso dele, o que faremos nas próximas lições. Mas vamos em frente e ler isso para que possamos ver o que temos. E, claro, para ter certeza de que está funcionando. Então, dando uma olhada nisso, temos as diferentes dicas e trabalhadores. E nas filas temos duas filas, o símbolo Q, bem como o upload do Postgres. E em nossos trabalhadores temos que dar uma olhada nisso. Em nosso worker é que teríamos vários diferentes e temos o trabalhador wiki, que também tem valores de entrada aqui, podemos ver que eles foram transferidos corretamente. Temos o nosso trabalhador do Yahoo Finanças vai fazer referência ao jovem amigo é agendador de preços. E o nosso trabalhador Postgres, que vai fazer referência ao programador mestre Postgres. Então agora nós meio que temos este pipeline completo, defina-o neste arquivo YAML. Novamente, é claro, ainda não fizemos uso dele. É o que faremos nas próximas seções. Mas espero que você possa ver que se nós pudermos transferir a descrição geral de como um programa funciona, em vez de como codificar tudo aqui para tê-lo muito mais configurável neste arquivo YAML. Isso nos proporciona muita flexibilidade porque, uma vez que criamos dinamicamente nossos funcionários e enviamos para cada uma dessas filas. Se quisermos adicionar outro banco de dados salvando em outro lugar. Mais tarde, dizemos que tudo o que também queremos salvar aqui realmente só tem que fazer é primeiro temos que escrever a classe para ele como fizemos aqui que pode cuidar disso. Mas então vamos apenas dizer que queremos salvar isso para eu não sei, algo como um banco de dados Redis. Então, vamos apenas adicionar outra fila. E então nós também vamos enviá-lo para cá. E então podemos dizer, oh, acabei de notar que há um erro de digitação aqui também. Então vamos em frente e consertar isso. Mas eu quero dizer, nós não escrevemos isso, é claro. Mas essa é a ideia. Tudo o que temos que fazer é uma vez que você vai e vai ser r em cubo. Então essa é a idéia de que uma vez que tenhamos a classe escrita para ela, ao invés de termos que mudar a ordem nossa função principal e tipo de adaptar tudo a isso. É muito mais fácil do que podemos apenas mudar os arquivos de configuração. E, na verdade, podemos criar vários arquivos de configuração diferentes para vários pipelines diferentes adorando querer executar, mas o código vai permanecer o mesmo. E são apenas os diferentes pipelines que temos disponíveis. Ou talvez você queira fornecer valores de entrada extras com esse tipo de formato. Espero que você possa ver que se torna muito mais fácil mudar, manipular, adicionar, remover ou até mesmo ter fluxos diferentes. Bem, apenas sendo capaz de reutilizar o mesmo código e tudo o que estamos mudando realmente é o fluxo geral, as configurações e coisas assim. Então, sim, vamos em frente e retirar isso porque é claro, isso não existe e nós não implementamos esse tipo de classe. Mas sim, apenas mais para um exemplo que você pode ver como podemos estender isso e como ele se torna tão versátil e útil. Porque novamente, estamos alterando este arquivo YAML aqui e podemos realmente criar vários arquivos YAML diferentes para vários pipelines diferentes que queremos executar. Nosso código permanece sempre o mesmo. 11. Como criar um leitor em Yaml: Tudo bem, então agora que temos esse arquivo YAML definido, que vai ser um pipeline. Vamos realmente ir em frente e implementar algo que pode ler este arquivo ou apenas tomar um arquivo geral que nós assumimos que tem este tipo de estrutura de trabalho cubo. E então ele só vai tratar o oleoduto para nós. Porque nosso trabalhador Vicki agora também não é uma ameaça de si mesmo, mas apenas como uma classe que faz o trabalho e apenas meio que retorna os valores para nós. Por agora. Eu vou apenas comentar este aqui fora. E podemos deixar isso em nossa função principal por agora e mais tarde, se quisermos, podemos mudar seu trabalho de refatoração wiki para trabalhar como nosso trabalhador do Yahoo Finance ou nosso trabalhador do Postgres, onde basicamente temos esse mestre thread do agendador, bem como o próprio trabalhador, mas pode cuidar do trabalho para que possamos realmente passar esses valores e ler de outro Q upstream que podemos então alimentar esses valores. Mas por enquanto, vamos deixar isso como está, e vamos nos concentrar em implementar sim, basicamente tudo o resto. Então eu vou criar um novo arquivo aqui. E eu vou ligar para este. Vou ligar para este leitor YAML. Poderíamos chamá-lo de algo mais como executar o Pipeline YAML ou o que for. Tudo bem, e então aqui, por enquanto eu só quero primeiro de tudo, e importar yaml. Isso é algo que vamos precisar, com certeza. E então vamos em frente e apenas definir uma classe e , em seguida, importar o resto das coisas como nós meio que precisamos dela. Então este vai ser o nosso oleoduto YAML. Acho que podemos chamar de executor de oleoduto amarelo. E então vamos em frente e executar o método de inicialização, que por enquanto vamos deixar o AS vazio. Você voltará para nós. Então, quais são os outros métodos que precisamos? Primeiro, precisamos de algo que processe algum tipo de oleoduto, certo? Temos de ser capazes de processar o gasoduto que queremos passar aqui. Portanto, há duas opções para nós tipo de passar índices neste pipeline. Um deles é que o colocamos aqui. Então nós podemos ter, nós sabemos o nome do arquivo ou o diretório e encontrá-lo aqui que podemos ler a partir dele. Ou podemos realmente inicializar o executor do Pipeline YAML com o pipeline que queríamos executar especificamente. Eu vou escolher isso porque eu acho que é um pouco mais agradável tipo de, você sabe, dizer que cada classe que você tem aqui é responsável uma vez que você tem uma instância como responsável por executar esse pipeline. Em vez de um executor de pipeline ser capaz de executar qualquer pipelines em, apenas torna um pouco mais fácil raciocinar sobre se você já inicializar ou se você já tiver vários pipelines para executar, você pode simplesmente inicializar diferentes executores de pipeline e tipo de nomeá-los de acordo, você um para cada pipeline, em vez de apenas reutilizar o mesmo, mas passar em diferentes pipelines mais tarde. Assim, pode ficar um pouco mais. Não é confuso, mas talvez como um pouco mais complicado para apenas segui-lo ou não é tão óbvio como você poderia obter, obtê-lo se ele fez isso com a inicialização. Então aqui eu vou apenas dizer localização do oleoduto, que vai ser três neles. Ou chamar nome do arquivo é porque ele vai ser um caminho que vai ser em como pipelines aqui. Então só quero que este tipo de ser como um local geral. Então vamos definir este atributo. Pipeline. Localização vai ser igual a este atributo que dissemos aqui. Vou escrever uma música. As diferentes partes do nosso oleoduto é, e se também olharmos para a nossa função principal, ok, então o que fizemos de errado? Necessidade de inicializar as pistas. Quantos inicializarão os trabalhadores? E então precisamos enviar feito para as pistas para. Então a primeira coisa, é claro que perdemos seus dois é que também precisamos ler e processar este arquivo YAML, ou talvez o processamento aconteça mais tarde, mas primeiro precisamos lê-lo. Então primeiro método que queremos ter este pipeline de carga. E daqui, eu estou colocando esses sublinhados aqui só porque sublinhados geralmente significam que é como um tipo de atributos internos ou método para a classe. Considerando que nenhum sublinhar métodos sobre que tipo de e para ser usado desde o início. Claro, você ainda pode acessar ambos em Python que este tipo de indica para você este é um método que eu quero usar internamente porque eu não quero mais ninguém sobre o código. Eu realmente não quero que eles chamem pipeline de carga. E assim este tipo de indica que isso está sendo usado internamente. Da mesma forma, aqui o local do pipeline está sendo usado internamente e não deve ser realmente confundido. Porque, você sabe, nós temos o local do pipeline definido a partir da inicialização. E é claro que devemos carregar o pipeline com o mesmo arquivo e isso só deveria acontecer uma vez. E isso deve ser um pouco predefinido e definido assim. Então, sim. Então temos que fazer aqui é que vamos abrir nosso suco de gosma. Tantas sugestões. Vamos abrir nosso arquivo e qualquer variável que você quiser. E nós vamos ter nossos dados YAML ser igual a camel dot arquivo de entrada de carga segura aqui. Lá vamos nós. Tudo bem, então isso é tipo do que fizemos em nossa última lição para apenas, você sabe, carregar no arquivo YAML aqui, colocá-lo neste atributo de dados YAML. Certo, então esse é o primeiro passo que queremos processar nossa sala de oleodutos. A primeira coisa que queremos fazer é ter certeza de que realmente carregamos este oleoduto n. Então agora que temos este arquivo YAML carregado em um objeto Python que podemos ler. A próxima coisa que queremos fazer. Além disso, se olharmos para nossa função principal, é que queremos inicializar nossos qs. Ok? Então vamos ter um novo método. Haverá vidas iniciadas. E eles são do tipo aqui, cubos. E sim, a partir disso nós só queremos inicializar Qs, ok, então agora precisamos rastrear nossas pistas de alguma forma. Então eu vou criar em nossa inicialização e outro atributo que vai ser o nosso QRS. E então vamos dizer para nome da fila, ou na verdade ele vai dizer para Q em nossos dados YAML. Porque o que estamos fazendo aqui é que temos, isso vem tipo de outro dicionário. Desde então, temos uma chave aqui, que é porque se você se lembra, não é, então vamos rapidamente, rapidamente dar uma olhada nisso novamente. Então vamos importar YAML. E então vamos pegar esse nome corretamente. Certos ensaios com oleodutos abertos cortam este servidor, ele diria: “Sim, eu não vou namorar nesta carga segura. Então é isso que vamos ter aqui. E assim em nosso primo podemos ver que temos esta lista aqui e temos as diferentes pistas com seus nomes como descrições pulsivas. Então o que vamos fazer é iterar sobre esses diferentes sinais que queremos. E para cada uma dessas dicas vamos realmente criar uma fila. Voltando à nossa função principal, basicamente vamos fazer isso. E para obter este Q, precisamos importar este cue de multiprocessamento. Então vamos fazer assim. E então para cada fila que temos, vamos dizer, ou podemos obter o nome da fila se quisermos, que será Q2. Nome. Nunca vou dizer, loops são nosso nome de fila específico em nosso dicionário cuz aqui vai ser apenas uma versão de lista inicial da classe fila de multiprocessamento. Então estamos fazendo a mesma coisa aqui. Mas ao invés de definir essas dicas como esta, é basicamente nós temos um objeto ou um dicionário que vai se parecer com isso. Claro, você sabe que os nomes que estamos usando são um pouco diferentes. Mas isto é como a ideia do que estamos a fazer. E, claro, temos a liberdade de mudar isso porque podemos, se adicionarmos mais pistas aqui, então isso vai cuidar disso. Mas realmente este é o formato que estamos recebendo aqui. E em vez de usar, e eu vou vê-lo em um segundo, vez de referenciar esta variável que contém o Q, podemos então apenas mais tarde em preferência que fila específica acessando o componente dicionário. Então ainda estamos fazendo a mesma coisa, mas dessa forma, nos permite primeiro distinguir nossas diferentes pistas porque temos nomes diferentes associados a elas. E também nos permite escalá-los um pouco mais facilmente dinamicamente porque temos um objeto que pode conter um 0 indefinido. Enquanto estamos escrevendo este número de código de dicas que podem subir ou descer conforme necessário. Mas sim, basicamente, você sabe, não é realmente nada diferente de colocá-los em uma, uma variável distinta. Mas não os acessamos diretamente sobre a variável, mas sim através de uma chave contida em um dicionário. Então é isso que estamos fazendo aqui. E, claro, é isso que queremos fazer. A próxima coisa que queremos fazer é, claro, inicializar as pistas. Tudo bem, então nós carregamos nosso arquivo YAML e nós cuidamos desta parte aqui. Então, agora vamos em frente e cuidar de inicializar nossos trabalhadores. Então. Esse será o nosso próximo método. Vamos inicializar os trabalhadores. Então, vamos dizer para trabalhador em dados YAML auto dot. E desta vez vamos passar por cima destes trabalhadores assim. E agora nós queremos, bem, antes de tudo, nós queremos manter o controle de cada um desses trabalhadores. Então nós queremos saber quais trabalhadores nós realmente temos disponíveis ou, você sabe, quais trabalhadores estão trabalhando atualmente? Então você vai manter o controle de nossos diferentes trabalhadores aqui, assim. E então, ok, então agora chegamos a um pequeno problema interessante porque estamos passando na classe, bem como a localização de onde podemos encontrar essa classe. Mas, na verdade, este é apenas um nome como se não pudéssemos inicializar isto. Enquanto que em nossa função principal, nós o importamos especificamente. Então, como podemos fazer isso? Bem, há uma biblioteca legal que podemos usar, que é chamada de lábio de importação, que gosta, nos deixa cuidar disso. Agora, outra coisa que você também percebe aqui, rapidamente apontando isso para fora é qualquer biblioteca que é instalado padrão irá para o topo. E então uma vez que chegamos a bibliotecas que são pip install e install a partir de uma fonte externa, nós vamos ser separados por uma nova linha, e estes serão agrupados juntos. E então podemos ver na função principal, fizemos a mesma coisa aqui. Então este é um interno vem com Python. Então temos uma nova linha, esta biblioteca e qualquer outra coisa que seja pip install irá aqui. E então temos uma nova linha. E estes são todos os nossos pedaços personalizados de código que estão contidos dentro do nosso próprio repositório aqui. Dessa forma, você sabe, somos capazes de separar um pouco mais facilmente os diferentes tiroteios de localização e é um pouco mais fácil deixar claro como o que pertence ao quê. Mais uma vez, isto é mais como uma coisa visual. Claro que tudo o que for necessário. Só faz com que seja um pouco mais limpo. Só queria apontar para o caso de você estar se perguntando por que estou fazendo isso. Então temos essa coisa importante. Então, é claro, o que precisamos é que precisamos da classe operária que possamos realmente inicializar. Então nós queremos ser capazes de ler esta classe de trabalhadores em geral para que possamos fazer algo assim. Mas é claro que não sabemos quais trabalhadores vamos conseguir porque esse pipeline pode realmente ser definido. No entanto, certo? Como se essa fosse a grande coisa. Mas, claro, 0 notou o ponto esquerdo da última vez. Essa é a grande coisa. Mas é claro que também temos de ser capazes de lidar adequadamente com isso. Então, para fazer isso, vamos usar o membro de importação ou, na verdade, se vamos usar primeiro atributo. E eu vou explicar, vamos escrever tudo e então eu vou explicar tudo aqui em um segundo. E vamos fazer o módulo de importação lib dot. E o módulo que vamos importar será o local de trabalho. Então vamos acessar o trabalhador específico e vamos acessar sua localização específica. E, em seguida, o atributo que queremos acessar. E mais uma vez, vamos escrever isto e depois repassar mais uma vez. Haverá a classe dos trabalhadores. Está bem. Então, o que acabamos de fazer? Bem, vamos dar uma olhada nos nossos trabalhadores. Então vamos dar uma olhada no nosso primeiro trabalhador aqui. Então realmente, você sabe, é claro que se nós estamos passando por cima desses trabalhadores, então nós vamos obter cada um desses elementos aqui um por um. Então nós temos o nome, et cetera, et cetera. Neste momento, estamos a olhar para a localização. Este aqui. Então isso nos dá essa coisa aqui, certo? Este caminho trabalhadores ponto yahoo Finance worker, workers dot yahoo Finance worker. A mesma coisa que fizemos aqui. Trabalhadores ponto yahoo Trabalhadores Finanças. Ok? Então nosso loop de importação vai importar este módulo assim. Então, basicamente, ele vai fazer algo como importação. E então ele vai apenas importar, importar isso. Basicamente meio que está nos permitindo fazer isso. Porque nós não queremos apenas todo este módulo, mas sim queremos obter uma classe específica a partir dele. Precisamos tirar um atributo específico desta classe. Agora, este é um método Python interno que basicamente nos permite acessar atributos. Na verdade, funciona da mesma maneira. Se tivéssemos uma classe definida específica, poderíamos ter nossa aula aqui e, digamos que quiséssemos. Temos o nosso cronograma do Yahoo Finance. Eu olho e dando uma olhada nisso. Então aqui temos as filas de entrada. Então, algo que poderíamos fazer para é que poderíamos dizer como Obter atributo aqui, e então temos as filas de entrada. Basicamente, esta é uma forma de tirarmos atributos de classes, ou, neste caso, também de módulos. Porque fazer algo assim não funciona para aulas e trabalhos ou dicionários, mas não funciona para aulas que precisaríamos fazer, é acessá-lo assim, certo? Mas e se quisermos acessar dinamicamente uma variável? Então não podemos simplesmente como se não houvesse uma boa maneira termos esta sintaxe se isto é suposto ser dinâmico. Então, a maneira que podemos fazer isso é usando este método get attributes. E, e isso dinamicamente nos permite definir o atributo que queremos tirar desta classe assim. Da mesma forma, podemos usar a mesma espessura, mas também funciona neste módulo de importação aqui. Então estamos importando e a partir dele estamos extraindo essa classe operária. Então basicamente essa coisa aqui é quase a mesma coisa que fazer isso aqui, exceto que nós já estamos especificamente, você sabe, nós temos essa classe que estamos fazendo agora. E nós o temos especificamente nesta variável de classe worker aqui para que possamos usá-lo e podemos inicializá-lo. Então, é claro que precisamos fazer isso porque, novamente, tudo isso pode ser definido à vontade. E então precisamos ser capazes de realmente importar a classe e usar ou inicializá-la e usá-lo sem saber qual classe vai ser. Nós meio que precisamos, desde que tenhamos esse formato de classe de localização, você sabe, desde que isso seja obedecido, precisamos ser capazes de importar isso e inicializá-lo. Certo, então temos nossa classe de trabalhadores, mas também precisamos de outras propriedades associadas a ela. Coisas tão importantes se olharmos para os nossos dois trabalhadores aqui é que precisamos da entrada q e precisamos do QS de saída. Se olharmos para o nosso trabalhador Postgres aqui, só precisamos da fila de entrada. Ok? Então vamos apenas ler a fila de entrada. E esse é esse atributo aqui que definimos com trabalhadores. Então, vamos dizer o nosso trabalhador. E aqui o que vamos é ao invés de apenas tentar acessar o atributo diretamente assim. Porque em alguns casos, por exemplo, se tivermos isso definido, isso não funcionaria porque nossas filas de entrada realmente não estão definidas aqui. Então, para estar seguro contra algo assim, nós vamos realmente usar um método dot get. Agora, quero te mostrar isso rapidinho. Então, se temos um dicionário, como este, dicionário muito simples, se você fizer x dot obter um, nós vamos obter o valor da chave a, que mapas para estar aqui. Mas se você fizer x ponto obter dizer, um ou a corda 1. Então este está procurando a chave. Esse valor não está aqui, então não vamos conseguir nenhum. Assim, desta forma, em vez de esta falha, ou ele vai obter o valor aqui se ele existe ou não existe, ele vai obter nenhum. Ok? Assim, nós podemos, você sabe, nós vamos ter certeza de que não falharemos aqui. Nós também queremos o QS de saída. E a partir daqui vamos apenas usar este formato. Vai ser o nosso QS de saída aqui. Ok? E vamos ver, precisamos de mais alguma coisa? Então precisamos de nossos valores de entrada e nosso cubo superior. Tudo bem, então nós temos isso dentro Mas atualmente nossa fila de entrada aqui, na verdade, será apenas um nome. Não é a fila em si. Então precisamos pegar essas dicas e então podemos passá-las para nossos trabalhadores. Então vamos sentar de cada vez, vamos criar uma nova variável que vai ser nossos parâmetros de inicialização. E aqui vamos passar a fila de entrada, que vamos definir. E nós também vamos nos ter por enquanto apenas as filas de saída, que também serão definidas em apenas um segundo. Tudo bem, então aqui nós realmente precisamos passar uma instância do bonitinho como este, certo? Não podemos simplesmente passar o nome. Isso porque é apenas um nome não ajuda. Então, para isso, temos nossas dicas aqui. Então o que queremos fazer é basicamente queremos obter essa fila de entrada aqui. Nós queremos pegá-lo. Queremos obter a instância de fila real. Então nós vamos dizer self.users dot input, oops, e colocar QM. Se você colocar q não é nenhum. Nenhum. Então, como definimos isso? Claro que precisamos da vírgula depois. Então, há apenas uma declaração se else que podemos escrever em uma linha para que não tenhamos que escrevê-lo sobre várias linhas. Misturar um pouco mais fácil de ter isso em que linhas, podemos ter toda essa lógica aqui diretamente. Então, se tivermos uma fila de entrada, então vamos tomar a instância real que definimos aqui e usar o que Q está associado a isso. Caso contrário, isso não vai ser nada. E aqui o que queremos fazer. É uma coisa semelhante, que vai ser, nós queremos. Agora, aqui temos que ter cuidado porque podemos ter vários QS de saída, certo? Então, queremos tornar isto mais como se quiséssemos fazer disto uma lista. Alguém responda a dizer aqui, off ponto-ponto de saída Q. para saída Q. e pistas. Se nenhum, é claro, isso é um pouco longo. Estou revisando o número recomendado de linhas? Podemos dividir isso em 2 íons colocando uma barra invertida aqui, o que nos permite dividir isso em duas linhas. Certo, então agora temos nossos parâmetros de inicialização. Novamente, o que isso faz é que nos permite quebrar uma declaração sobre várias linhas sem quebrar a lógica. Porque se fizéssemos isso ou a lógica estaria quebrada, certo? Só temos esta lista aqui. E, em seguida, a próxima linha que iria executar a instrução. Vai ser fora deste ano de barra invertida. Ele realmente junta essa lógica e basicamente diz que esta lógica continua na próxima linha. E desta forma nós simplesmente não temos que lidar com esse texto transbordante. Tudo bem, então temos a célula Parâmetros de Inicialização de nossas instâncias de trabalho aqui. Então vamos realmente seguir em frente e inicializar nossos trabalhadores. Então, primeiro de tudo, eu só quero também querer obtê-los ou poderia nomear, é claro, nome próprio. Vai extrair o nome. Então, para cada nome de trabalhador, por agora eu vou apenas criar uma lista vazia para ele e, em seguida, vamos anexar as diferentes causas de trabalho. Então, por enquanto, vou dizer corretores autodidata que o trabalhador chamado Dot Append e ter essa classe de trabalhadores aqui. E vamos passar para ele os parâmetros de inicialização. Então isso nos permite fazer, é pegar este dicionário e basicamente transforma cada dicionário aqui em um par de valores chave que podemos passá-lo. Então o que aconteceria neste caso é fazer isso é o mesmo que ter algo como se nossa entrada q aqui não é nenhum loop como este. E isso seria, por exemplo, autodidata porque se tomarmos, bem, vamos, vamos dar o exemplo para o jovem trabalhador financeiro. E eu só estou supondo aqui. E então vamos rever o que está acontecendo. Então esta estrela, estrela basicamente descompacta este dicionário e para cada chave aqui, tem a chave aqui é esta, e então mapeia para um valor específico no dicionário como este. E faz isso dinamicamente. Então, se você adicionar mais parâmetros aqui, então todos estes, você sabe, cada um deles será definido em um mapeamento de pares de valores chave aqui. Então isso é realmente bom porque meio que nos permite descompactar nossos parâmetros de inicialização e passá-los individuais, como pares de valores-chave aqui para que possamos definir especificamente como este é um muito peculiar suas filas de saída, claro, para isso funcionar, precisamos ter certeza de que são nomeados aqui, entrada q e q. Então isso já vai ser um problema porque eu chamei essas filas de saída, mas isso é chamado de saída cubed aqui, então que ele vai criá-lo assim. Agora, outro problema, é claro, é se fornecermos parâmetros aqui que não existem. Por exemplo, neste caso, nós dois temos entrada aqui. Nós não temos um Q. Então realmente se nós apenas temos isso aqui, então ele iria reclamar porque nós estamos passando saída Q como um parâmetro de inicialização. Mas não existe no trabalhador Postgres. Mas é aí que estas estrelas, estrela k funciona. Ou argumentos de palavra-chave vem em. Basicamente nos permite passar em um conjunto E de argumentos de palavra-chave. Então qualquer coisa que é definido com a palavra-chave e definido igual a algo sem realmente ter que se preocupar com, você sabe, como as repercussões. É meio que pega e então podemos fazer com ele o que quisermos se quisermos usá-lo. Neste caso, nós apenas passá-lo para o segmento para a classe pai. Mas também podemos ignorar completamente isso e não fazer nada com ele. Olá. Essa é uma maneira muito legal de fazer isso porque nós podemos apenas desempacotar este dicionário e imediatamente, você sabe, passá-lo aqui. E sim, então quase temos a lógica que temos aqui. Ainda faltam algumas coisas. Por exemplo, aqui estamos definindo o número de trabalhadores que atualmente não temos. É uma solução fácil para nós, porque podemos entrar aqui. E podemos dizer, por exemplo, instâncias. Digamos que queremos formulário. E eu vou pegar a mesma coisa e colocar isso aqui. Isto não tem de ser a mesma ordem. Novamente, estamos recebendo um mapeamento de dicionário a partir disso. É apenas uma hora conveniente para ser a mesma ordem. E aqui podemos dizer, ou digamos que queremos muitos trabalhadores Postgres, mas não queremos tantos purificadores. Então agora podemos dizer que o número de instâncias que queremos é apenas obter os atributos de instâncias daqui, assim, e, em seguida, apenas inicializá-lo uma vez que vamos dizer I no intervalo do número de instâncias. E queremos criar trabalhadores Domini. Aqui. Na verdade, provavelmente seria melhor para nós fazermos algo assim. E nós também podemos realmente fazer é colocar um padrão ou um parâmetro fallback. Então, neste caso, se voltarmos para este ponto x a, obtemos o valor b que está associado ao k aqui. Se fizermos x ponto ponto queria existir. Mas se fizermos isso, isso significa que se ele não existir, então nós voltamos para isso. Então, se por algum motivo as instâncias que não estão definidas, sabemos que queremos trabalhar para isso porque está no pipeline. Então, vamos usar apenas um. Caso contrário, se as instâncias artefato e nós vamos usar isso. E assim, agora podemos aumentar dinamicamente se quisermos ou diminuir sempre que quisermos o número de trabalhadores aqui, e vamos apenas criar esse número de trabalhadores. E então a última coisa que queremos fazer é, é claro que queremos chamar esse método de auto-ponto inicializar workers. E então nós também queremos ser capazes de se juntar aos trabalhadores como nós temos aqui. Então os trabalhadores e já dissemos para o trabalhador em, os trabalhadores dirão para distorção nome e trabalhadores e, em seguida, vamos dizer para o segmento do trabalhador. Então lembre-se que temos um, este é um dicionário e cada chave aqui é o nome do trabalhador. E, em seguida, com cada valor, vamos ter uma lista. E cada uma dessas listas será uma classe de trabalhadores. Então, cada um deles será um fio em execução. Então, queremos fazer um loop sobre cada segmento. E então aqui nós chamávamos o ponto juntar-se assim. Tudo bem, então esta vai ser a turma. E nós vamos parar aqui por agora porque nós estamos obviamente esta classe está implementada em qualquer lugar ainda, mas isso vai ser uma espécie de, isso forma a base de sua classe que nos permite fazer todas essas coisas. Então, as seguintes lições vamos implementar esta classe e meio que movê-la para nossa função principal e, você sabe, funcionalidade ali. Nós vamos fazer qualquer depuração, é claro, porque nós não fomos capazes de testar esta classe em tudo, certo, agora apenas meio que foi escrito assim. Então é provável que haja alguns bugs aqui que precisaremos corrigir. Alguns também fazem isso e, em seguida, tipo de assumir isso. E talvez, em seguida, também mudar uma funcionalidade um pouco para que possamos realmente ter o nosso worker wiki aqui também ser algo que podemos definir especificamente como queremos ser capazes de talvez passar em vários URLs. Sim, mas sim, acho que vamos fazer isso nas seguintes lições, já que você não quer nos arrastar por muito tempo aqui. 12. Como melhorar nosso trabalhador em Wiki: Muito bem, agora que temos esta YAML vamos procurar. Vamos realmente ir em frente e implementar isso em nossa classe principal, porque agora estamos em nossa função principal, porque agora nós apenas temos este custo bom, mas nós realmente não estamos fazendo muito com isso. E ainda não está perfeito, como veremos em um segundo. Mas vamos dizer pelo rigor M, vamos importar o executor do Pipeline YAML. Tudo bem, então nós vamos ter nosso executor do Pipeline YAML ser igual a. E agora precisamos definir a localização do pipeline. Então a nossa localização de pipeline a partir de agora vai ser pipelines slash wiki, Yahoo de cobre pipeline dot YAML. Agora isso é codificado o suficiente. Idealmente, ele irá mover isso para variáveis de ambiente, mas vamos fazer isso mais tarde. Vamos pôr isto a funcionar por enquanto. Tudo bem, então isso não precisamos mais porque temos nosso executor do Pipeline YAML ou trabalhadores wiki. Interessante, porque ainda precisamos disso. Não precisamos mais disso. E isso também não precisamos mais. Então precisamos mudar nosso pipeline de processamento um pouco, porque não podemos, veremos em um segundo, mas ainda não podemos nos juntar aos trabalhadores. Porque neste momento há um tipo de um acaso. Não por acaso, mas como se fosse um pouco ainda não fosse perfeito porque temos algumas coisas dentro da YAML e executá-la e algumas coisas como veremos em um segundo ainda sem ele. Então, se nós realmente chamarmos o pipeline de processo aqui, nós vamos carregar o pipeline. Vamos inicializar um QRS e trabalhadores. Nós não queremos nos juntar a ele porque se fizermos isso, então, você sabe, eu sou basicamente todos os trabalhadores estavam meio que terminaram e então nós não colocamos nada ainda, mas nós não podemos colocar nada ainda, porque os q só são inicializados quando nós realmente inicializar a fila e a etapa do pipeline do processo aqui. Então, infelizmente, por agora, vamos resolver isso mais tarde, mas por enquanto vamos ter que desligar esse lugar aqui e vamos ter que ligar manualmente mais tarde. Não estamos manualmente, vamos subir para ligar mais tarde. Então temos o nosso símbolo Q. Agora, o Q que queremos. Por enquanto, vou usá-los. valor codificado será este símbolo Q aqui. E, claro, agora queremos fazer todo esse tipo de oleoduto YAML, eu acho que aqui. Então, mas por enquanto vamos apenas testar a funcionalidade. Então você vai entrar em nosso executor de pipeline YAML. Nós vamos realmente acessar este atributo. E aqui vamos acessar o símbolo Q, porque é onde isso precisa ser escrito. Então essa é a chave que queremos escrever, é claro, sintaxe não-ideal. Mas porque o nosso trabalhador wiki não é realmente definido o pipeline e dentro do ureter meio que tem que fazê-lo assim por enquanto. Tudo bem. Em seguida, imprimir feito depois. Por isso, neste momento, ainda temos de o fazer. Hum, então por enquanto, nós, porque agora podemos definir como o número de diferentes instâncias aqui por nós mesmos. Vamos pegar um pouco de tampa superior grande. E nós vamos dizer, em vez de, você sabe, especificamente dizer algum número, nós vamos apenas dizer 20 quadros. Mas é claro que isso também não é ideal. Mas, sabe, vamos fazer isso ser assim por enquanto. Vamos colocar feito para o símbolo q. e aqui onde os fios estão sendo unidos, assim por diante. Ok. Então agora temos que juntar nossas ameaças e mostrar alguma outra sintaxe, tentar e trabalhadores. Vamos nos certificar de que se juntam aos lurkers, certo? Tudo bem, então vamos em frente e ver se funciona. Provavelmente bugs que temos que corrigir. Muito bem, então o nosso trabalhador Postgres obteve um argumento de palavra-chave inesperado Q. Então vamos dar uma olhada nisso. Trabalhador Postgres aqui. Tenho uma verdade inesperada. Onde está o nosso problema? Trabalhadores inicializados, classe de trabalho. Ok, então acho que o problema é que você está fazendo Postgres Master Scheduler. Não, esse não é o problema. Mestre Postgres. E obteve a saída inesperada do argumento de palavra-chave Q. Então, olhando para o nosso registro aqui, parece que isso está reclamando assim que fazemos a super inicialização. Então talvez ou a nuvem de encadeamento é, classe de threading está realmente reclamando sobre isso. Então vamos testar isso. Vamos para Python. Vamos importar. Escrevendo, vamos dizer rosca de ponto. E vamos apenas tentar a saída Q é igual a a. Então é aí que o problema está. Então vamos confiar, colocar esta saída Q aqui, para colocar esta saída Q aqui, que não passemos para os argumentos de palavra-chave aqui. Alternativamente, você também pode fazer é que podemos removê-lo deste dicionário usando esta chamada pop, que vai apenas removê-lo e realmente tipo de dar-nos o valor aqui, mas ele vai apenas removê-lo dos argumentos de palavra-chave. Então, e aqui provavelmente queremos ter alguma segurança. Quer dizer se a saída Q e argumentos de palavra-chave, então queríamos apenas removê-lo. Então vamos tentar correr o tempo daquela mulher. Tudo bem. Até agora não há enfermeiras, provavelmente bom sinal. Tudo bem. Então chegamos a algum tipo de tempo limite que está bem. Mas parece que terminou. Então tivemos algum tipo de tempo divulgado por qualquer motivo por enquanto. Mas é claro, desta vez eu venho daqui. Tão jovem. Além disso, parece que está funcionando. Então isso é realmente muito bom. Isso significa que podemos pegar esse código e podemos ver o que resta e o que mais precisa ser implementado. Certo, então é claro, uma das coisas que queremos mudar é que tudo isso não é muito legal, certo? Como idealmente, teremos o trabalhador wiki. E todo esse processo em que mantemos os valores dos trabalhadores estão sendo alimentados. E tudo isso está sendo feito neste toco de pipeline de processo. E assim não temos que chamá-los de juntar-se e recorrerem aqui em baixo também. Então, como vamos fazer isso? Então, a melhor maneira que isso ou não, eu acho que a maneira que eu mais gostaria é que nós tipo de estender para este trabalhador wiki. E basicamente o que vamos ter como sendo querer ter um tipo similar de opção onde temos essa masterclass que podemos fornecer valores para. E a partir desses valores, então nós vamos ter, você sabe, instâncias de trabalho wiki ou apenas uma única instância de trabalho Wiki, talvez isso vai cuidar disso. Então o que podemos fazer é que podemos ter um programador mestre de trabalho wiki. E nós também vamos realmente ter isso ser uma instância de thread de ponto de rosca. Já está em crédito para nós. Legal. Então a razão para isso é porque em nosso leitor YAML, nós realmente vamos chamar o método join. E caso contrário, desta forma Nós obter como uma boa chamada do método join porque ele vem herdado da classe thread. Mas, caso contrário, precisaríamos defini-lo nós mesmos para que quando chamamos de “juntar-se “, você sabe, não quebre. E você poderia até fazer isso fazendo algo assim. Só o torna disponível. Você sabe, se, se ele não veio herdado da classe pai, apenas para que ele não quebrar neste passo para que possamos seguir o mesmo tipo de ordem lógica. Mas vamos realmente torná-lo uma ameaça e vamos em frente e inicializar o pai. Aqui vamos tomar argumentos de palavra-chave. Mais uma vez, frequente passar para o pai de rosca. Sim. Fim. O que queremos no nosso trabalhador Vicki aqui chamado de uma das coisas que queremos fazer. Claro, não posso esquecer se você quer começar. E então nós também temos que ter taxa unclass aqui. E nós vamos fazer algo, você sabe, enquanto o que quer que isso seja verdade. Ok? Então, o que queremos no nosso programador mestre do Mickey? Então, se olharmos para trás em nossa função principal aqui, queremos que nosso worker basicamente seja capaz de talvez pegar URLs de entrada diferentes, criar um worker wiki com cada URL, e então fazer com que o wiki worker tipo de passar por seu processo obtendo os símbolos e apenas colocando-os em um Q. Então, o que precisamos para isso do que precisamos se a saída Q. E daqui, queremos ter certeza de que você não passa a fila de entrada porque isso vai receber a mesma reclamação. Então nós vamos dizer se a nossa entrada q está em nossos argumentos de palavra-chave, nós apenas removê-lo e apenas pulou para fora disso. E outra coisa que queremos, porém, é que realmente queremos algum tipo de entradas que possamos passar, certo? Como se não tivéssemos uma fila de entrada porque não íamos ler a partir de uma fila de entrada, mas queremos entradas que possamos iterar sobre. Então vamos dizer, vamos assumir que vamos passar e entradas vão dizer entradas. E é claro que não queremos passar entradas também. Então, espaço de entradas para tomar daqui. E vamos sair de novo assim. Tudo bem, então sim, então este é o tipo de formato que queremos. Claro, nós também queremos realmente definir a saída Q para o acusado. E vamos realmente usar a mesma sintaxe que estamos usando aqui. Para que possamos definir vários QS de saída, se apropriado. Pensamos da maneira que podemos, se voltarmos para aqui, dessa forma, sempre que obtivermos valores, se quisermos, podemos colocá-los em diferentes filas de saída para que, você sabe, diferentes trabalhadores upstream possam usá-los para qualquer finalidade. Usando isso para, tudo bem, Se Q2 e ok, então agora precisamos definir essas entradas e nós também vamos mudar nosso método run aqui. Então, ao invés de dizer que é verdade, vamos dizer para entrada e empreendimento é porque agora nós realmente temos um número limitado de entradas que esperam que nós queremos passar por isso. E eu sou uma soma de classificação. Vamos atualizar nosso arquivo YAML para que nossa wiki ocorra. E ao invés de inicializar o Bucher maluco do braço, queremos inicializar o programador mestre do trabalhador wiki. Nós chamamos esses valores de entrada. Então, se você quiser, podemos atualizar a partir de entradas aqui dois valores de entrada. Isso é totalmente bom. A questão é que eu tenho que ter certeza de que nós, naturalmente, também fazemos isso aqui. Ok? Então, queremos ter valores de entrada aqui. E, em seguida, para cada valor de entrada como este, queremos iterar sobre estes. E para cada um desses valores de entrada, nós só queremos colocar esses valores na saída do símbolo Q aqui. Tudo bem, então temos nossas entradas aqui. Então, para cada entrada, vamos ter em nosso Wiki Corker, queremos inicializar isso. Nós realmente queremos inicializá-lo com um URL específico. Então o que vamos fazer é mover a URL para os parâmetros de inicialização aqui. E assim podemos inicializá-lo diretamente para as diferentes entradas que vamos fornecer por aqui. E agora, nós também precisamos, bem, se nós voltarmos para a nossa função principal, nós podemos iterar sobre os diferentes símbolos e então nós queremos colocá-los em nossa saída Q. Então, por enquanto, nós podemos apenas assumir essa lógica usando o contador de símbolos para isso. A única razão pela qual estamos usando isso é novamente, lembre-se, para que nós não colocar todos os símbolos na saída Q para que nós estamos eliminando todos esses valores diferentes, aplicá-los em Postgres. E, mas sim, nós apenas fazemos os cinco primeiros apenas para ter certeza de que está funcionando. Nós não precisamos fazer como todos os 500 agora. Então nós vamos assumir este alojamento e nós vamos ter, eu sou mais velho. Eu vou dizer quatro fora, colocar q em nossas filas de saída. Então, para cada saída Q, Oops, Não, queremos ter certeza de que colocamos esse símbolo lá. Certo? Então vamos passar por essa lógica aqui. Então temos o nosso programador mestre de trabalho wiki, que vai ser uma instância da classe thread. Para isso, vamos tomar argumentos de palavra-chave e saída Q. E se não tivermos entrada q e queremos ter certeza de que removido para que não passá-lo para a inicialização da classe pai threading. Nós também queremos valores de entrada, e esses valores de entrada serão diferentes URLs que podemos definir aqui assim. E, claro, para a nossa saída porque queremos ter certeza de que temos a opção de ter diferentes pistas alfa para que possamos ter aqui, por exemplo, como símbolo Q2 e como segundo símbolo Q. E se nós temos isso, deixe-me também é claro precisa defini-lo aqui em cima, mas, você sabe, apenas se queremos colocar isso em mais de um Q, então eu sou mais de um tipo diferente de trabalhador pode consumir este downstream que nós temos essa opção. Tudo bem, queremos ter certeza de inicializar um fio pai. E então queremos começar o processo, assim como fazemos aqui. Agora, para isso funcionar, nós também precisamos do método run, que vai ser chamado Tipo de que pode ser cuidado automaticamente para nós porque estamos jogando pai. Mas diferente dos nossos trabalhadores a jusante que vão estar à espera de valores até que saiam do QRS e os leiam. Diferente disso. Não estamos lendo de uma aguda aqui, mas estamos lendo de um conjunto predefinido de entradas. Então, sim, nós só queremos ter certeza que estávamos passando pelo conjunto predefinido de entradas que temos aqui, porque nós já sabemos quais são esses valores. Então nós não precisamos, você sabe, tentar pegá-los de algum tipo de bonitinho. Então vamos rever os diferentes URLs de entrada. Para cada entrada, você vai criar um worker wiki. Este trabalhador wiki vai cuidar do desmantelamento, então encontrar cada um dos símbolos. Então vamos ter essa mesma lógica aqui. E para cada símbolo que obtemos, queremos colocá-lo para o QS de saída, já que podemos ter vários jovens olímpicos, queremos ter certeza de que nós loop sobre cada Q. superior E então este material aqui, isso é realmente apenas para que nós não sucata 500 símbolos, mas apenas fazer os primeiros cinco apenas para fazê-lo ir um pouco mais rápido. Tudo bem, então vamos pegar essa saída e no final. Então, esta é também a lógica que queremos mudar para o nosso trabalhador rápido. E no final aqui, eu quero dizer para a saída Q e as pistas superiores. E aqui de novo, vamos dizer como um número ridículo agora. 20. Queríamos ter certeza que enviaríamos. E só queremos que isso aconteça depois de todos os símbolos terem sido enviados. E então, uma vez que tudo isso acabar, nós podemos realmente enviar feito. Então não precisamos mais disso aqui. Não precisamos mais que se juntem aos trabalhadores porque podemos fazer isso agora. E aqui. E eu vou escrever, e vamos dar uma olhada nisso. Tudo bem, então vamos em frente e tentar saber, ver o que acontece. Veja se perdemos alguma coisa. Certo? Então ele está procurando valores de entrada 0, 0, curso, e nosso leitor amarelo. Nós também precisamos ter certeza de que passamos ouvir. Assim, os valores de entrada são iguais a ponto de trabalho. No entanto, valores de entrada. Na verdade, vou fazer isto aqui em baixo. E eu vou dizer, se eu usar não é uma anomalia, então eu quero colocá-los nos parâmetros de inicialização. A razão pela qual estou fazendo isso, ao invés de sempre fornecer a média e os parâmetros de inicialização, como fazemos aqui, é porque nossos valores de entrada são como um caso especial, especificamente para nosso trabalho wiki aqui, Certo? Porque em todos os outros trabalhadores estão lá para entrar acusados, talvez não o acusado com eles vão ser genuinamente como filas de entrada e saída. Mas os nossos valores de entrada só serão específicos para o nosso único trabalhador aqui. Então, em vez de colocá-lo aqui e, em seguida, indo para outro worker e certificando-se de que esta fila de entrada, esses valores de entrada não são passados como argumentos de palavra-chave até o thread, como a inicialização de threading aqui. Só vou passar se estiver lá dentro , e assim eu só preciso cuidar disso aqui. Certo, então vamos tentar de novo. Nenhum erro até agora, o que geralmente é um bom sinal. Mas vamos esperar e ver o que acontece. Tudo bem. Legal. Parece que as coisas estão funcionando. E sim, nós temos o nosso trabalhador wiki agora que, você sabe, está tomando todos esses valores. Mas, claro, para ter certeza que as coisas estão funcionando, vamos apenas ir em frente e imprimir em nosso funcionário Postgres recebeu isso apenas para ver se ele chega todo o caminho, todo o caminho para baixo fluxo. Certo, então está recebendo valores. Então tudo está funcionando, o que é incrível. Há, é claro, ainda uma coisa que não está funcionando, que é que não está recebendo feito corretamente o tempo todo e não é como provavelmente fugir. E a razão para isso, se nós entrarmos no trabalhador Yahoo Finanças, é na verdade ele só está colocando feito aqui. E então o problema aqui neste caso é, se formos aqui, temos duas instâncias, mas aqui temos seis instâncias. Então você vai notar que a diferença, seis menos dois é quatro. Temos quatro instâncias que não estão recebendo, que são feitos sinal agora. Então, o que podemos fazer por agora só vai acabar com isso porque eles estão fugindo. E nós vamos dizer aqui, para alfa q e para cima acusar bilhete vai apenas dizer para eu na faixa 20. Para cada saída Q, vamos apenas enviar um monte deles. Claro, isso não é ideal porque se tivermos 21 trabalhadores e muitos do mesmo problema, mas por enquanto, você sabe, deve ficar tudo bem. Então, podemos reexecutar isso rapidamente. A outra coisa que você também vai notar é que ele não definiu instâncias aqui. E assim você pode ver que, ótimo, e tudo funcionou bem porque nós não definimos como as instâncias aqui. Isso cuidou disso. Agora este é outro pequeno tipo de nuance que temos porque aqui nós realmente não queremos várias instâncias. Porque se tivermos várias instâncias, elas não estarão consumindo da mesma fila, mas sim repetirão esse processo. Então aqui nós realmente não queremos várias instâncias porque se o fizermos, como eu disse, eles não estão consumindo de uma fila. Então eles não estão pegando um taco e dividindo o trabalho. Eles vão estar repetindo o trabalho porque a maneira que isso funciona é que ele vai realmente iterar sobre este conjunto de valores de entrada. Então aqui precisamos ter cuidado que só temos 11 instância. Então podemos deixar, por exemplo, em nota, ter apenas uma instância aqui. Caso contrário, eliminamos este símbolo. Então, é claro, você sabe que há maneiras diferentes de fazer isso. Uma coisa que poderíamos fazer é que poderíamos novamente como um separado isso fora e você sabe, apenas ter nosso próprio trabalhador wiki consumido de uma fila. E nós alimentamos esses valores de entrada em q em si. Mas em algum momento, você sabe, nós precisamos, você precisa chegar ao ponto em que nós temos um worker que só tem uma instância que apenas alimenta todos esses valores de entrada em uma fila que o trabalhador wiki poderia então consumir. Então, por exemplo, nós poderíamos ter como outro trabalhador aqui, apenas vai ser, você sabe, URL cedro. E este aqui pode tomar como este aqui poderia levar esses valores de entrada. E, em seguida, as filas de saída. As filas podem, por exemplo, ser saídas de URL. E então aqui e coloque Q, podemos ler a partir daqui. E neste caso, como este trabalhador vai ser aquele que só pode ter uma instância. E talvez seja, você sabe. Então, como este problema vai ser como estendido para a frente, para cima. Mas neste caso, podemos ter vários threads aqui porque eles não vão mais ler a partir de valores de entrada, mas eles vão estar criando a partir da fila de entrada. Hum, então se você quiser, você pode realmente brincar com isso e implementar isso para que nós possamos realmente suprimir diferentes Reino Unido ou então ao mesmo tempo se tivermos mais de uma instância aqui. Mas sim, é claro, em algum momento nós vamos estar correndo para este problema onde nós precisamos apenas fornecer algum tipo de semente. E se tivermos mais de uma instância fornecendo-lhes a direção c e começando duplicatas. Então, sim, você sabe, apenas estar ciente disso, esse problema simplesmente existe. E assim podemos deixar uma nota, por exemplo, para dizer como apenas ter uma instância aqui. E podemos até deixar isso claro novamente, podemos dizer a primeira instância e podemos dizer: Por favor, não nos mude. Caso contrário, fazemos trabalho duplicado, algo assim. Veja você nota acima. E executamos isso mais uma vez só para ter certeza que está funcionando bem e colocar q este não existe. E se tudo está funcionando corretamente, mas, você sabe, apenas tipo de estar ciente disso. Nós não queremos ter mais de uma instância aqui porque estamos iterando sobre estes como valores de entrada definidos manualmente aqui. Mas acabou por um minuto. Sim, olhando para o nosso resultado e olhando para a nossa função principal, as coisas estão realmente parecendo muito boas. A única outra coisa que podemos fazer, é claro, é se quisermos ter tempo de execução adequado. E nós colocamos isso no topo aqui porque de outra forma provavelmente começando este tempo de cobre depois disso, mas nós estamos chamando juntar-se a trabalhadores aqui. Então só vamos começar isso quando todo o trabalho estiver feito. Então, se você quiser ter o tempo adequado, e é claro que precisamos colocar isso acima assim. E nós também podemos remover todas essas importações não utilizadas aqui porque todas essas importações foram agora movidas para o nosso leitor amarelo. Nós podemos apenas economizar e rumores ou mais tempo para ter certeza de que isso está funcionando corretamente. Mas agora isso é muito bom, porque veja como nossa função principal se tornou pequena. Tornou-se tão simples. Só temos o oleoduto que queremos executar. E então nós apenas temos nosso pipeline executar ou que cuida de tudo. E agora, se quisermos fazer mais trabalho, então, você sabe, podemos estender isso. Nós podemos, se tivermos mais URLs que é seguir a mesma estrutura que acreditamos que nosso trabalhador wiki pode cuidar. Então você sabe, nós podemos colocar em mais valores de entrada aqui. Podemos estender isso para ter perspectivas diferentes. Normalmente, falamos anteriormente sobre talvez salvar dois bancos de dados diferentes ou algo assim. E, claro, você sabe, se criarmos um trabalhador extra, precisamos ter certeza de que definimos esse trabalhador também. Mas realmente todo o trabalho duro foi transferido para o leitor amarelo. Esta coisa realmente cuida dinamicamente de apenas este arquivo de configuração YAML aqui. Então realmente como se pudéssemos estender isso tanto quanto quisermos. Claro, como a única coisa que precisamos fazer se adicionarmos um tipo diferente de trabalhador, precisamos ter certeza de que, você sabe, definimos a classe de trabalhador e tudo o mais e garantir que isso esteja funcionando corretamente. Mas uma vez que tenhamos a classe operária disponível, podemos reutilizá-la. Podemos estender nossos oleodutos, certo? Condutas diferentes. Há um monte de coisas legais que podemos fazer e tudo o que podemos definir sobre esses arquivos YAML muito legível e de fácil manutenção. Portanto, é tão fácil para nós escalar para cima e para baixo o número de diferentes trabalhadores que queremos ter. Se vemos, por exemplo, nossos trabalhadores Postgres um gargalo. Porque realmente tudo é apenas uma espécie de espera para ser salvo em Postgres pode aumentar o número de instâncias. Ou se ele está indo bem, podemos realmente deixá-lo como está, ou mesmo diminuir o número de thread não é muitos. Queremos aumentar o número de raspadores que temos. Então, há tanta liberdade para nós, tipo, sintonizarmos nossos oleodutos aqui. E tudo isso foi movido para este arquivo YAML e nosso código prateado, nós apenas tipo de dinamicamente cuidar de tudo isso. 13. Melhoria em todos os trabalhadores e adição de monitoramento: Tudo bem, então nesta etapa, vamos limpar nossa arte YAML Pipeline executa ou um pouco mais, apenas olhando para fora nossa função principal aqui, realmente o que estamos fazendo é chamar essa etapa de pipeline de processo, onde fazemos tudo, desde como carregar o pipeline e, em seguida, inicializá-los como filas e trabalhadores. E então, claro, chamar esse lugar aqui para que, você sabe, esperemos que todos esses trabalhadores terminem. E se nós apenas olhar para a maneira que, Vamos ver em nosso trabalhador wiki, por exemplo, aqui. Então a maneira como estamos lidando com o envio feito agora não é ideal. Porque o que estamos a fazer é enviar isto, digamos, 20 vezes. O que é, bem, é um pouco estranho porque imagine que temos vários desses trabalhadores correndo ao mesmo tempo. Então, neste caso, se vamos enviar feito, mas um dos outros trabalhadores não está realmente feito. E nós estamos enviando feito mais do que nós temos esse número de trabalhadores abaixo do fluxo, então eles estão realmente todos indo para ler feito e eles vão estar parando. Apesar de talvez algum outro trabalhador, você sabe, ainda colocando valores naquela fila mais tarde. Agora, é claro, neste caso, bem, podemos ter isso para o trabalhador do Yahoo Finance, por exemplo, para o trabalho wiki atualmente não são tanto porque estamos limitando as instâncias aqui a um. Uma vez que precisamos ter certeza de que basicamente fornecemos esta semente não duplicada. Mas isso não pode acontecer com o trabalhador do Yahoo Finance. Se um deles termina logo antes do outro, e ele apenas coloca tudo lá e então o outro ainda está funcionando e colocando alguns para uso enquanto então todos os trabalhadores a jusante vão estar lendo isso e realmente não vão estar recebendo os valores finais que não estão neste cubo. Então, nesta etapa, vamos otimizar isso um pouco. E vamos pegar isso enviando o sinal para fora de nossos trabalhadores e vamos movê-lo para o nosso principal trabalhador. Essencialmente, nós apenas atualmente não somos um trabalhador, é apenas uma espécie de classe que nos ajuda a executar o pipeline. Mas, na verdade, vamos importar rosqueamento. E vamos fazer disso um fio 2. Então vamos torná-lo basicamente nosso principal trabalhador. E aqui o que vamos fazer agora é que estamos, bem, claro que precisamos adicionar a etapa de execução. Aqui. Nós vamos ser cuidados de monitorar o progresso e enviar comandos concluídos uma vez que tudo é feito. Então, também vamos estar tirando que se juntam aos Trabalhadores. Porque o primeiro passo que vamos fazer quando esse processo começar é que vamos realmente estar enquanto estiver executando a etapa de pipeline de processo. Então, se nos juntamos aos trabalhadores aqui, então basicamente tudo vai ser bloqueado até chegarmos a este ponto. Então, é claro, não podemos ligar para os trabalhadores e na verdade nós nem precisamos dele porque também aqui nós vamos ter como um loop infinito que é basicamente apenas indo para cuidar de tudo, pode cuidar de todo o monitoramento, etc, parede, tudo o resto está ativo. E para isso, então, é claro, nós também temos que apenas começar o nosso segmento para que, você sabe, começa a correr. Certo, então o que vamos fazer aqui? Bem, realmente o que queremos fazer é saber para cada trabalhador, primeiro lugar, quantos, como o q está enviando dois, e também quantos trabalhadores ainda estão vivos. E então o que queremos ser capazes de fazer é, uma vez que todos os trabalhadores não estão mais vivos, queremos enviar feito para todas as filas de saída para as quais ele envia. Então, por exemplo, se temos três QS de saída aqui e este é feito, então queremos enviar feito para todas essas filas de saída. E, idealmente, o número de vezes que enviamos feito também depende de quantas instâncias estão realmente consumindo dessa fila. Então vamos ter uma coisa separada que apenas nos ajuda a rastrear quantas instâncias são, quantos trabalhadores estão consumindo de cada fila. Então vamos em frente e configurar isso. E nós vamos realmente fazer isso parte de nossos trabalhadores inicializados. Mas primeiro vamos realmente colocar isso em nosso método inicializado função inicializada aqui. Vou escrever algumas coisas e explicar o que estava acontecendo com eles. Podemos recapitular novamente uma vez que está fora, porque uma vez escrito, obviamente será um pouco mais fácil entender a lógica ao invés de explicá-la em um sentido mais abstrato. Então vamos ter aqui consumidores Cube. E também vamos anotar as pistas a jusante. Então a variável Q consumidores é basicamente vai dizer, para este símbolo Q, isto é quantos trabalhadores estão consumindo desta fila. E o primo a jusante é basicamente sempre vai ser o trabalhador e o que é porque é sentido também. Então esses são os dois atributos extras que estamos adicionando aqui para que possamos manter o controle dessa informação porque vamos precisar dela mais tarde. Então, agora, quando estamos inicializando nossos trabalhadores, temos que manter o controle de, bem, antes de tudo, que dicas faz isso certo? Dois. Então temos o QS de saída. Claro. Aqui. Então nós vamos ter, nós vamos adicionar aqui em nossas pistas a jusante. Para este trabalhador vai estar escrevendo duas filas de saída sim. Agora observe que estamos pegando os nomes do QS de saída aqui para que possamos referenciá-los mais tarde aqui. Mas nós realmente não precisamos tomar a instância da fila. Podemos rastrear o nome aqui. E então também queremos saber o que Q está sendo consumido. Então, se temos uma fila de entrada aqui, e então podemos dizer, se a entrada q não é nenhuma, então queremos observar aqui este Q como sendo consumido por tantos trabalhadores, certo? Então, dependendo do número de instâncias que temos aqui, e isso é quantos trabalhadores serão consumidos da fila. Agora, com isso, temos uma suposição implícita de que cada fila será para um trabalhador. Então, por exemplo, se temos um segundo trabalhador que quer fazer uso dos resultados daqui, ele não vai estar lendo a partir desta fila porque isso está basicamente espalhando nossos valores sobre dois trabalhadores separados que serão fazendo duas coisas separadas. Se você quiser armazenar esses dados brutos em algum lugar, então nós temos que ter uma saída separada Q, para que nós não perca nenhum valor que basicamente os dois trabalhadores, um deles vai ser o processamento e o outro que vai ser apenas armazenar os valores brutos. Eles não querem ler do mesmo cubo porque então eles são como compartilhar os dados e uma das partes dele estão sendo salvas e outras partes de ser processadas. Mas realmente queremos que cada passo neste pipeline processe todo o conjunto de dados. Então, se precisamos deste conjunto de dados 2, então precisamos adicionar outra saída Q aqui para se certificar de que podemos usar o conjunto de dados completo. E com isso e o que estamos escrevendo aqui, novamente, estamos assumindo que cada UC é específico de um trabalhador. Então, se estamos consumindo do símbolo Q aqui, então nós não podemos consumir do símbolo Q com um trabalhador separado em outro lugar, porque caso contrário, eles vão estar dividindo os dados aqui porque eles estão apenas indo para levá-lo para fora. Então essa é uma suposição implícita que estamos fazendo aqui. Ok? Mas agora nós temos, você sabe, agora sabemos qual trabalhador o que Q cada trabalhador está escrevendo, e também o q, quantos trabalhadores estão consumindo de cada fila. Tudo bem, então temos o processo Run aqui. Então agora o que queremos fazer é basicamente, e podemos definir isso em um intervalo. Então eu também vou importar o tempo porque isso nos permite ter uma função de sono no final. Então talvez nós dormimos por cinco segundos no final. Para que não gostemos de fazer isso continuamente, mas basicamente fazer isso em intervalos. Então aqui vamos fazer o nosso monitoramento. Então o que queremos fazer é basicamente para cada trabalhador e para cada segmento e cada trabalhador, nós só queremos verificar se ele ainda está funcionando. Hum, então o que isso significa? Se olharmos para o nosso trabalhador do Yahoo Finance, por exemplo, uma vez que saímos desse loop aqui, e basicamente esse método chega ao fim, então o worker não está mais em execução. Nesse ponto, o trabalhador já não está vivo. E então, basicamente, queremos estar procurando os pontos quando, por exemplo, este worker quebra de seu loop de execução ou termina seu método de execução aqui. Nesse ponto, já não está vivo. Nesse ponto sabemos, ok, este trabalhador terminou. Então podemos começar a enviar e fazer para os consumidores a jusante. Claro, se tivermos mais instâncias do que precisamos para ter certeza de que não é apenas uma instância que terminou, mas que é cada instância que terminou. Então o que vamos fazer é dizer para trabalhador, nome de trabalhador, e agora só queremos levar nossos trabalhadores. Então, voltando sobre os nossos trabalhadores. E aqui vamos manter o controle da vida total dos segmentos de trabalho. Então, como cada um de nossos trabalhadores pode ter vários threads, nós só queremos manter o controle do número total de threads que estão sendo executados no momento. Então nós vamos estar looping sobre cada lado. Nós vamos dizer para o segmento do trabalhador, assim como aqui, looping sobre cada segmento que mantemos o controle aqui. Então, como podemos verificar se é Lifo? Na verdade, é relativamente fácil. Tudo o que temos que fazer é pegar nosso fio e podemos apenas usar este método está vivo. E isso nos dirá se o trabalhador ainda está vivo ou não. Então podemos dizer se um trabalhador está vivo. Então só queremos incrementar isso por um. Então, basicamente, para cada trabalhador que temos que está vivo, então vamos incrementar isso por um. E então, no anterior, se não tivermos nenhum desses trabalhadores vivo, então se todos os tópicos tiverem terminado, agora podemos começar a pegar as pistas a jusante daqui, e podemos começar a enviar feito para ele. Então podemos dizer, tudo o que precisamos para obter os sinais a jusante. E quatro aqui, temos que verificar primeiro, se não nenhum, porque não podemos ter casos. Por exemplo, nosso trabalhador do Postgres não tem filas de saída. Então queremos ter certeza de que os sinais a jusante que temos, que estes existem. Então, se a redução cues ou não nenhum, então nós queremos, para downstream Q nas dicas a jusante que temos para cada trabalhador. Então o que estamos fazendo é fazer um loop, Aqui está um arquivo YAML. Estamos fazendo loop sobre cada um desses QS de saída aqui. Desde que isso vai, o que estamos acompanhando nesta variável cuz downstream é que estamos mantendo o controle de todas as filas de saída. Então podemos chamar isso para Q. Nós podemos chamar essa saída Q para tipo de ser mais realmente consistente com uma sintaxe que temos aqui. Então, podemos usar isso para rotear para cada saída Q e aqui. Depois, queremos ter um número de consumidores. Então agora queremos saber para cada saída Q, quantos threads estão realmente lendo a partir daqui. Bem, nós rastreamos isso bem aqui. Então, sabemos para cada q quantos tópicos ou leitura a partir dele. Então, o número de consumidores aqui. Podemos ler deste dicionário que criamos antes aqui. E então podemos dizer para eu em número de gama de consumidores. E agora para cada um destes, podemos enviar feito para este Q. de saída Então nós realmente temos que obter este FAQ. Então, eu vou recapitular em um segundo. Mas primeiro, vamos escrever isso para que tenhamos, você sabe, a coisa toda aqui. Então vamos tomar nossa saída Q. e assim como temos aqui, vamos colocar feito. Tudo bem? Ok? E então a última coisa que talvez possamos fazer, se não tivermos mais dessas ameaças vivas, então podemos realmente remover, podemos remover esse tipo de trabalhador do nosso rastreamento para que não precisemos mais de uma pista. E agora, ok, então como vamos sair desse loop infinito enquanto nós também queremos manter o controle do total de trabalhadores vivos. E basicamente, nós provavelmente podemos fazer isso aqui em cima porque queremos manter o controle disso em cada iteração. Então toda vez que estamos passando e para cada um dos trabalhadores, nós queremos saber, você sabe, quantos trabalhadores e total vivo. Vamos rever todos os trabalhadores. E então aqui nós podemos realmente dizer, bem, nós podemos fazer enquanto verdadeiro, e então você pode dizer aqui, se o total de trabalhadores vive é igual a 0, então nós podemos sair disso. Ou podemos dizer, enquanto total de reservas vivo porque não é igual a 0. Mas é claro que temos que defini-la aqui e gritar. Então, neste caso, qualquer uma dessas opções está bem. E isso realmente depende do que você quer ir com, eu acho que aqui. Bem, já que temos isso agora e nós vamos apenas tipo de ir com isso. É um pouco estranho ter essa duplicação aqui. Neste caso, eu também poderia colocá-lo na parte de trás para que basicamente recontemos, redefinamos o contador no final. Mas realmente não está indo bem. Nós realmente não queremos redefinir o contador no final porque então nós estaríamos quebrando este loop. Então, sim, nós queremos tê-lo no topo aqui. Certo, então vamos rever o que temos. E, na verdade, a primeira coisa também que eu vou fazer é eu vou apenas comentar todas essas coisas fora porque nós não queremos mais que nossos tópicos, é claro, estão enviando esses sinais feitos. Mas, em vez disso, queremos que o nosso gasoduto principal seja responsável por isto. Então, o que acabamos de fazer? Bem, em primeiro lugar, tiramos os trabalhadores da nossa etapa de processo. Porque se fizermos isso, então basicamente este passo aqui será bloquear e nós não queremos isso. Então nós tiramos isso deste passo aqui. E em nossos trabalhadores inicializados, adicionamos dois atributos extras que estamos rastreando. Cada um deles tem um dicionário. Então, para cada trabalhador, para rastrear o Q, eles enviam dois. Então estamos rastreando sua saída Q. E para cada q, estamos também, são para cada trabalhador, também estamos rastreando como o q eles lendo e quantas instâncias estão lendo da fila. Novamente, assumindo que cada sugestão é específica para um trabalhador. Então não podemos reutilizar o símbolo Q, por exemplo. Aqui, como se isso não funcionasse porque então eles vão estar espalhando os dados que vêm daqui. E isso vai estar lendo um pouco dele, e isso vai estar lendo um pouco dele. Mas nenhum deles vai obter o conjunto de dados completo e completo. Então não podemos fazer isso. Então, com essa suposição, estamos basicamente dizendo, Ok, cada tipo de trabalhador e podemos escalar o número de instâncias aqui ainda sem problema. Mas cada tipo de trabalhador que temos aqui tem uma fila específica associada a ele de modo que sabemos agora, ok, para cada q, sabemos que isso é quantas instâncias estão consumindo a partir dele, que podemos ver aqui. Ok, então agora estamos apenas mantendo o controle das estatísticas Q. Então, mais tarde, quando chamamos este método de execução ou, e, em seguida, as próximas etapas deste método de execução e trazer você está usando a execução porque nós transformamos isso em uma classe de threading. Estamos agora começando um loop que basicamente vai manter o controle de como monitoramento para nós em uma mão. Na verdade, vamos começar a implementar o monitoramento em um segundo. Mas também vai ser cuidar de enviar feito para as filas de saída. que novamente é importante porque se fizermos isso aqui, do que uma ameaça poderia terminar, eu poderia começar a enviar feito, e outro thread poderia estar em execução, e ele vai realmente estar adicionando valores após o feito aqui tem foi enviado. Mas, você sabe, com isso, estamos enviando umas 20 mensagens terminadas. Em seguida, os consumidores a jusante estão realmente todos indo parar porque eles vão estar recebendo o valor w1. E então eles vão ser algumas mensagens na fila que vão ser deixadas não lidas. Portanto, queremos evitar isso e só queremos enviar feito uma vez que cada trabalhador tenha terminado. Então, a maneira que estamos fazendo isso é que estamos passando por cima de cada trabalhador que temos. E para cada trabalhador estamos revisando cada linha e estamos apenas verificando se esse fio está vivo ou não. E agora o que isso significa é que um thread não está mais vivo se ele terminar seu método de execução aqui. Então, basicamente, se ele sair desse loop de execução, esse ponto de thread não está mais vivo. E isso não dispararia. Mas se ele ainda está vivo, isso significa que ainda está neste circuito de corrida aqui. E então estamos apenas mantendo o controle do número total de threads de trabalho que estão vivos. E se nenhum dos fios estiver vivo, isso significa que todos os trabalhadores terminaram. Está quebrado se for loop. Então nós sabemos, ok, agora queremos enviar feito para todas as pistas que ele escreve. Então precisamos fazer loop sobre cada saída única Q, m para cada saída única Q, precisamos enviar feito um número de vezes com base no worker que lê a partir desta fila, que é este. Quantas instâncias esse bar? Então, por exemplo, neste caso, temos seis instâncias lendo do Postgres upload. E então queremos ter certeza de que enviamos feito pelo menos seis vezes para que cada instância aqui leia a mensagem concluída. E essa é a lógica que implementamos aqui. E, no final, estamos tirando esse trabalhador do rastreamento para que, você sabe, uma vez feito como se não precisássemos mais fazer a mesma coisa. Nós sabemos, como uma vez que enviamos tudo isso aqui, então, você sabe que o trabalhador está totalmente acabado. Não precisamos mais rastreá-lo. Então, há mais uma coisa que eu só quero acrescentar aqui, que vai ser estatísticas de trabalhadores. E o que eu quero fazer aqui é adicionar o nome do trabalhador, assim como quantos trabalhadores estão vivos. E então, no final aqui, eu queria imprimir as etapas do autoworker. Agora isso é apenas um tipo de monitoramento para que possamos realmente ver o que está acontecendo. E aqui em nosso segmento principal, eu meio que substituí este pipeline de processo foi apenas o passo inicial para que nós realmente iniciar este método de execução aqui. Certo, então você não está apenas ativando meu ambiente virtual. E então vamos em frente e correr e realmente precisa ligar Postgres para. Porque agora minha instância Postgres ou servidor Postgres não está sendo executado localmente, então só precisa ter certeza de que é iniciado. Então vamos ver, lá vamos nós. Tudo bem, então vamos em frente e executar isso. Ok, temos um erro aqui. O método de inicialização não é chamado. Então, queremos inicializar a ameaça, é claro, também. Tudo bem, então vamos tentar isso mais uma vez. Certo, então está funcionando de novo. Então, para isso atualmente, bem, em primeiro lugar, nós temos esse tempo de extração novamente, que é só porque nós não estamos chamando eles métodos de junção. Então isso é meio como a mesma coisa que tínhamos antes de chover porque não vamos chamar “Junte-se aqui”. Basicamente salta para ouvir quase imediatamente. Mas a outra coisa é, parece que ainda não estamos imprimindo as estatísticas aqui. Então eu vou, é claro. Isso é meio que um erro aqui. Se definirmos isto para 0 aqui em cima, então é claro que nem sequer vamos entrar neste loop. Então deixe-me consertar isso. E aqui em cima, digamos que era o meu botão. Se definirmos isso como 0, se aqui, e então se dissermos, enquanto isso não for 0, bem, isso já é 0, então nem vamos entrar nesse loop. Então tire isso. Mas há mais uma coisa que eu queria fazer, que é ter uma lista de trabalhadores que devemos excluir. E em vez de excluí-lo imediatamente aqui, eu realmente quero anexar o nome do trabalhador e, em seguida, excluí-lo mais tarde. Então eu quero ser capaz de ouvir talvez para o trabalhador e excluir aqui, eu queria liderá-lo. A razão é que se apagarmos aqui em cima, ainda estamos iterando, como se ainda estivéssemos em loop sobre isso. E assim, para excluir enquanto estamos fazendo loop, então Python vai ficar chateado conosco. Então não queremos fazer isso. Só queremos remover uma vez que terminemos o loop, é por isso que estou a mantê-lo assim. Então vamos tentar isso mais uma vez. Ok, lá vamos nós. Então agora estamos vendo nossas estatísticas reais de trabalhadores. Assim, podemos ver o nosso trabalhador wiki aqui terminado. E nós também notamos meio que subindo aqui. Estamos vendo nove trabalhadores aqui, que é claro que não é verdade. Isso não é errado nosso monitoramento, porque aqui queremos mostrar o total de threads de trabalho vivos, não o número total de réplicas vivas, que é uma espécie de agregá-lo. Agora algo que deveria estar acontecendo, mas não está realmente acontecendo. E eu só vou tirar esse tempo de sono aqui só para ter certeza de que isso não é um problema. Mas podemos ver através de nossos registros que, na verdade, nossos trabalhadores estão atingindo tempos limite e que eles não estão sendo parados de nossos sinais de parada. Então, é claro que não queremos isso. Queremos ter certeza de que seus tempos limite estão sendo atingidos átomos. Então não queremos isso. Queremos ter certeza de que, você sabe, nossos trabalhadores estão realmente parando com o método que estamos fazendo que nós temos aqui. Então, dando uma olhada novamente em nosso loop, bem, isso deve ser não é nenhum. Porque queremos ir se tivermos trabalhadores a jusante. Então vamos tentar isso mais uma vez. E lá vamos nós. Então, agora resolvemos o problema que tínhamos anteriormente, que era que não estávamos enviando feito a partir daqui, mas sim atingindo tempos limite. E, claro, podemos ver que foi ótimo ter esses tempos limite porque ele meio ajuda a combater alguns dos bugs reais que tivemos aqui. Nós não estávamos meio presos em um loop infinito. Mas sim, então nós meio que terminamos essa parte, o que é realmente extremamente legal porque agora nós não estamos mais enviando feito a partir daqui. Então vamos em frente e remover isso também. E assim quando temos várias instâncias, então não é se o primeiro termina e ele envia feito, então, você sabe, todo o resto a jusante vai parar. E mesmo se nós só enviar feito uma vez, então lá nós entramos em problemas como o que acontece se enquanto o número de trabalhadores a jusante não é igual ao número de trabalhadores que temos atualmente. Se tivermos mais trabalhadores a jusante e eles não terminarem e chegarão aos tempos limite. E mesmo que o façam, vão parar antes que todos os trabalhadores parem, o que significa que o nosso rendimento vai diminuir. Então, tê-lo desta forma, É muito mais agradável porque agora estamos enviando feito. Uma vez que sabemos tudo isso, todos esses trabalhadores já terminaram. Agora há mais uma coisa curta que eu queria mostrar a vocês e eu sei que estamos ficando um pouco longos aqui, mas na verdade não podemos executar isso porque infelizmente ele não funciona no Mac, mas isso funciona no Linux. Então, estamos mantendo o controle de nossas estatísticas de trabalhadores aqui. E nós provavelmente não gostaria de fazer uma coisa semelhante para q diz que é certo, apenas entender sobre a quantidade de dados é realmente em nossas dicas. Agora, há este método se olharmos para a fila. Então, de novo, não vai ser como escrever tudo porque não vai funcionar de qualquer maneira. Mas podemos dizer como para Q em, em nosso QRS e, em seguida, apenas ter essa fila. E então aqui podemos olhar para o tamanho da fila. Então isso é novamente, algo que não está disponível, infelizmente no Mac, mas no Linux, isso é algo que você pode realmente fazer é obter os tamanhos das filas. Agora, hum, e isso é apenas muito legal porque basicamente, você sabe, você é capaz de monitorar quanto está em cada fila. E com isso, então você é capaz de dizer, Oh, ok, você conhece tantos trabalhadores ou tem, mas eu posso realmente ver como, oh, este Q super cheio. Então eu vou realmente adicionar mais instâncias lá e talvez eu levar alguns trabalhadores para outro lugar onde o tamanho da fila é sempre 0. Então, ter esta ferramenta de monitoramento Q também é muito bom. E claro que podemos colocá-lo em como também como oh, Q começa assim. E então aqui nós podemos, você sabe, exatamente como fizemos antes, em vez de apenas imprimir isso. Você pode adicionar isso aqui e então aqui podemos imprimir como pontos acusados. Agora, infelizmente, e você vai ver se eu executar isso, isso vai causar um erro porque basicamente isso não é implementado no Mac gentilmente. Então isso seria executado em um sistema Linux, mas infelizmente ele não é executado no Mac. Então, sim, não podemos usá-lo aqui. Mas na maioria das vezes, se você é realmente como usar coisas em produção e provavelmente vai ser executado em um sistema Linux porque ele será implantado em como uma imagem Docker ou algo assim. Então, nesses casos, você é realmente capaz de deixar este pedaço de código em. E você também poderá monitorar as estatísticas das filas. E com isso, então você será capaz de obter mais informações através dos registros. Aumente o número de instâncias postgres. Eu reduzo o número de instâncias, talvez porque é sempre 0. E assim não há nenhum ponto em ter que muitas instâncias se o nosso q é sempre 0. E então sim, sem esperançosamente você é capaz de pegar essas informações que você está recebendo e tomar decisões mais inteligentes sobre como você é, quantas instâncias você realmente está atribuindo a cada um dos diferentes trabalhadores que você tem aqui. Mas sim, isso meio que nos leva ao fim desta otimização aqui. E estamos chegando muito, muito perto de terminar isso. Então, a única coisa que resta, que é o que vamos abordar no próximo vídeo, é basicamente queremos pegar algumas das definições que temos, especificamente como a localização do pipeline ou algo assim. E nós queremos, ou eu quero colocá-lo em como uma variável de ambiente. Mas novamente, falaremos sobre isso na próxima lição. 14. Limpeza final de programas: Tudo bem, então nesta lição nós vamos apenas estar fazendo alguma limpeza rápida, basicamente indo e apenas movendo isso para uma variável de ambiente, mas então também tendo como uma variável de ambiente local que podemos usar para testes reais e outras coisas assim. Então só que tudo isso se torna um pouco mais livre baseado em sempre que queremos iniciar o programa, podemos tipo de defini-lo nesse sentido. Então você é, é claro, a primeira coisa que vamos fazer é dizer que este ambiente começa, eu vou chamar isso de nossa localização do oleoduto. E aqui também precisamos importar o sistema operacional. Agora o que eu vou fazer é eu vou criar um arquivo ENV ponto, que vai ser nossas variáveis de ambiente. E eu estou realmente, deixe-me renomear isso porque eu vou chamar isso de pensamento e local. Então isso vai ser como nossas variáveis de ambiente local. Isso significa que se queremos ter mais tarde como staging e variáveis de ambiente de produção, então podemos mudar cada um desses n dependendo do que queremos testar. Podemos usar coisas diferentes. Eu sou principalmente você quer estar testando provavelmente no local e encenando. Então vamos definir nossas variáveis de ambiente aqui. E nós só vamos, apenas vamos levar isso aqui. Então, o que este especialista nos permite fazer em um segundo quando usamos este comando source, é que somos capazes, enquanto somos capazes de obter o arquivo do ambiente. E então o que significa é que esta exportação só terá como definir essas variáveis de ambiente em nosso terminal aqui. Dessa forma, podemos apenas, você sabe, tê-los definidos em nosso terminal, em nossa instância de terminal em execução. E então, quando executá-lo, então nós vamos estar usando essas variáveis de ambiente. Então nós adicionamos o local do pipeline, mas na verdade, vamos passar por um worker diferente porque em nosso trabalhador Postgres também estamos usando variáveis de ambiente. Então temos Postgres usuário, que vai ser apenas uma string vazia. Nós temos a senha Postgres, que também vai ser uma string vazia, e o caso do Mac no caso do Windows aqui você vai ter valores definidos aqui. O anfitrião Postgres vai ser o nosso anfitrião local. E o banco de dados Postgres será o que temos aqui. Neste caso, na verdade, vou remover isto daqui. Assim, só temos isso definido aqui. Tanto quanto eu sei, este sourcing de ambiente e esta sintaxe é específico para como sistemas Linux e Mac. Mas você sabe, se você está em um Windows, você ainda pode ter a sintaxe semelhante novamente, como falamos sobre a última lição. Você realmente vai ser, você sabe, se você está fazendo isso ou alguém está ajudando você a implantá-lo em algum lugar, que isso é principalmente sempre vai ser executado diferente de um sistema baseado em Linux. Então, você sabe, você será capaz de usar este ambiente. E a sintaxe do ambiente funcionaria em um Windows também. Mas especificamente como esta sintaxe explorando desta forma, tenho certeza que é exatamente como Linux e Mac específico. Mas não se preocupe com isso, porque isso é como os estágios finais da limpeza. E novamente, se você estiver rodando em outro lugar, você pode realmente passar essas variáveis de ambiente. E então temos nossas variáveis de ambiente aqui. E nós temos aqui. Aqui precisamos dizer, se não temos um local de oleoduto, então basicamente vamos sair com um código de saída. Conjuntos falharam e nós vamos dizer, Eu sou a localização do pipeline não definida. E então se quisermos ter o tempo de extração do seu tubo, porque nosso executor principal, nossos executores YAML I, na verdade, também uma ameaça agora, bem nós poderíamos fazer é bem, poderíamos chamar isso de mostrar trabalhadores. Mas realmente sabemos que olhando para isso, nosso fio principal aqui, ou nosso fio de trabalho amarelo, só vai sair do ânodo uma vez que todos os trabalhadores e Saturno terminarem. Então, só uma vez que todos os trabalhadores lá dentro terminem vamos mesmo fugir daqui de qualquer maneira? Então realmente nós também podemos chamá-lo, chamar a junção aqui se quisermos obter este tempo de extração. Então vamos em frente e testar como isso está funcionando. Nós vamos ativar nossas variáveis de ambiente local para que possamos ver se eu quero imprimir esta variável. Ok, então agora está definido. E este eco é apenas um comando terminal que podemos usar. E este símbolo de dólar aqui basicamente significa que queremos imprimir acesso ao valor de uma variável, que definimos aqui. Então isso é muito semelhante, assim como definir variáveis em Python é apenas, a sintaxe é um pouco diferente para como o terminal, mas é basicamente imprimir o valor da localização do pipeline. E aqui estamos definindo a variável de localização do pipeline para ser desse valor. Tudo bem, então vamos tentar executar nossa função principal novamente e apenas ter certeza de que tudo está funcionando corretamente. E depois de fazermos essas mudanças, o que parece ser. Certo, e então também temos tempo de extração adequado. E então mais uma coisa que eu quero fazer é, quero dizer, nós provavelmente não queremos estar imprimindo todas essas coisas o tempo todo. Sabe, isso é mais para fins de teste enquanto estávamos tendo ele. Então nós podemos apenas remover essa impressão e eu executá-lo mais uma vez só para ter certeza de que a saída está limpa também. Então tudo parece muito limpo. E sim, lá vamos nós. Este tipo de como nos traz também poderia remover este basicamente qualquer desnecessário comentou coisas. E sim, este tipo de nos leva ao fim de todo este tutorial de threading onde nós construímos e você sabe, todo esse programa de threading para fazer como desmantelamento e upload de banco de dados e todas essas coisas só para se locomover. Os problemas são como os tempos limite que experimentamos na época eram os períodos de espera que estão associados à comunicação de rede. Então eu espero que você tenha gostado disso, você aprendeu muito e você é capaz de transferir parte disso para seus próprios projetos ou seu próprio trabalho. E novamente, fazer uso disso especificamente nos casos em que os fatores limitantes são tempos de comunicação de rede. Novamente, o threading não é ideal para otimizar cargas de trabalho pesadas de computação porque não estamos fazendo uso de CPU mais semelhante. É só quando estamos à espera que as redes respondam. Temos comunicação de rede do que outros threads podem continuar em execução enquanto os outros threads estão apenas aguardando alguma resposta de algum outro lugar através da rede. Então, de novo, você sabe, ótimo trabalho em completar esta seção do curso. Espero que tenha gostado. Espero que tenha aprendido muito. 15. Bloqueio: Tudo bem, então agora que nós construímos aqueles aplicativos de rosqueamento muito legal e algo que nós usamos muito dentro realmente eram todas essas dicas, que se você se lembra bem no início quando estávamos falando sobre o QRS. Vamos ver onde os inicializamos aqui. Então conversamos sobre isso ser seguro para threads. Então, o que exatamente isso significa? E esta lição, eu rapidamente quis passar por cima do bloqueio e algo conhecido como condições de corrida para que você possa entender algumas coisas que você pode precisar ter cuidado ao fazer rosqueamento. Então eu vou criar um novo arquivo aqui. Vou ligar para não trancar. E o que vamos fazer aqui é apenas importar rosqueamento. E nós vamos ter uma pequena função. Vamos ter um contador global que será definido como 0. E nós vamos ter uma pequena função chamada incremento. E isso vai levar o nosso balcão e nós vamos ter um loop aqui. Vamos dizer para eu no alcance, e então começar com 10. Estou usando poderes de 10 aqui, modo que on-off para escrever dez e, em seguida, um 100 e 1000. Então eu vou usar poderes de 10 só para tornar isso um pouco mais fácil e você vai ver o porquê em um segundo. Então nós vamos ter um loop aqui que atualmente apenas faz dez iterações. E durante cada iteração ele vai implementar um contador por um. Agora, aqui eu estou apenas chamando a variável global no caso de você não ter visto isso antes é uma vez que estamos modificando esse valor, nós realmente precisamos ter certeza de que nós chamamos a variável global no topo aqui, já que nós não estamos apenas acessando, mas estamos realmente modificando-o. Então agora o que vou fazer é criar quatro tópicos. Eu vou dizer para eu no intervalo quatro, nós vamos criar um fio. E nosso alvo será essa função de incremento. E então nós vamos apenas anexar estes e então nós vamos começar todos eles. Então vamos dizer t dot start. E, em seguida, vamos também chamar o método join para ter certeza de que esperamos até que tudo esteja pronto. E então, no final, vamos imprimir nosso valor de contador. programa muito simples. Realmente o que estamos fazendo é que temos uma variável global aqui, contador inicializado para sigma. E então nós apenas temos uma função que vai levar essas variáveis globais que vai incrementado dez vezes. E nós vamos rodar isso em quatro tópicos. Então, cada thread vai chamar essa função. Então, no total, devemos ter um valor aqui de 40. Uma vez que temos quatro threads, cada thread chama a função. Cada chamada de função irá incrementar este valor em 10, então 4 vezes 10, que vai ser 40. Então vamos em frente e executar isso. Tudo bem, pois parece muito bom. Então vamos tentar incrementar esse número aqui. Em vez de fazer dez, vamos fazer 1000. Então vai ser 10 para o 3. Tudo bem? E vamos em frente e executar isso. Certo, quatro mil, é exatamente o que esperamos. Tente incrementar isso mais uma vez. Em vez de fazer 1000 operações, agora vamos fazer um milhão. Então, o que esperamos ver aqui será de 4 milhões. Uma vez que cada valor vamos apenas aumentar um milhão de vezes e vamos fazer isso em quatro tópicos. Então vamos em frente e executar isso. Oh, bem, isso é estranho. Por que estamos recebendo isso e não 4 milhões? Então o que encontramos aqui é algo chamado de condição de raça, onde basicamente temos uma variável compartilhada, que é o que temos aqui. E várias entidades diferentes estão tentando acessá-lo ao mesmo tempo. Então o que está acontecendo em algum momento é que temos nosso contador, que é igual a qualquer valor x. e então temos um segmento. Um segmento lê e vê oh, contadores x. E então ele vai tentar incrementá-lo depois. Mas, ao mesmo tempo, temos outro segmento, digamos thread T2, que também vê contador é igual a x. Então, o que acontece é quando temos thread um está dizendo contador é igual ao contador mais um. Então isso significa que um contador de essência é igual a x mais 1. E então nós também temos linha para fazer a mesma coisa. Então temos neste caso é o resultado que obtemos é realmente contador é igual a x mais 1, mesmo que tivemos dois threads acessá-lo. E a razão pela qual isso acontece é porque às vezes esses valores basicamente eles vêem a mesma coisa e então eles chamam suas operações, mas eles não leram sequencialmente. Então eles não leram um após o outro. Não foi executado assim. Nesse caso, teríamos tido o valor adequado aqui, mas eles lê-lo ao mesmo tempo ou perto o suficiente antes que essa operação de incremento possa acontecer. Que Após essa operação de incremento acontece entre os dois threads. E neste exemplo, ainda ficamos apenas com x mais 1 porque eles viram o mesmo valor inicialmente. E então este é o tipo de problema que estamos vendo aqui. É óbvio que estamos a ver acontecer muito mais de uma vez. Mas podemos ver isso à medida que essas operações nesses segmentos aumentam. E neste caso, só temos que aumentar esse número para garantir que aumentemos nossas chances de algo assim acontecer. Estamos entrando nesta condição de corrida onde o valor está sendo acessado por vários objetos ao mesmo tempo, cada um está executando a operação e, em seguida, sua substituição do valor. Mas às vezes as mudanças que estamos recebendo não são as que esperamos. Uma vez que dois segmentos ambos incrementam x por um. E então não estamos recebendo um mais dois aqui, estamos recebendo um mais um. Agora, obviamente, este nem sempre é o caso porque nós temos, você sabe, nós estamos, nós estamos quase a meio caminho. Se eu olhar para esses números, grite, então estamos a meio caminho. Mas, obviamente, isso está acontecendo bastante. Então, o que podemos fazer sobre isso? Bem, há uma coisa legal chamada fechadura, que também é por isso que chamamos o nosso arquivo aqui de bloqueio. Então vamos para a aula de encadeamento e vamos inicializar uma fechadura. Agora, os dois métodos que estão disponíveis nesta classe de lei que realmente de interesse para nós serão bloqueados ponto adquirir e Locke, Locke dot release, comentar esses para fora. Então estes são os que serão testes interessantes. E o que estes fazem é colocar um, basicamente iniciar uma fechadura. Então, neste ponto, esta é uma operação de bloqueio e nada mais pode acontecer enquanto esta fechadura é adquirida. Então, este tópico basicamente reivindica o bloqueio. E está dizendo que eu estou correndo agora até que ele solte ou até que qualquer outro segmento liberte esse bloqueio, então nada que não possamos mais encontrar essas, essas condições de corrida. Então o que acontece neste caso é uma ameaça. A ameaça vai começar e vai ler a contra-variável. Mas o primeiro fio vai começar e vai dizer, Oh, eu estou garganta é, fio está travando. E, em seguida, ele vai ler a variável de contador. Vai incrementá-lo em um. E então é meio que dizer liberando a fechadura. E então vamos ter um segmento diferente, que também vai bloquear. E então ele vai ver o resultado aqui em cima, que é x mais 1. E então nós vamos ter x mais 1 mais 1, que vai ser x mais 2. E então estamos novamente liberando a fechadura. Agora, obviamente, neste caso, estamos meio que quebrando um pouco do paralelismo que estava disponível para nós e meio que forçando operações sequenciais. Agora, obviamente, não queremos trancar tudo o tempo todo, porque caso contrário, não vamos ganhar muito benefício. Mas, novamente, se você pensar sobre isso até o início, estamos usando threading, principalmente quando temos operações de E/S de rede bloqueando. Então, quando há muito tempo gasto entre viagens de ida e volta na rede, e não queremos ficar sentados ociosos esperando por uma resposta. É quando o threading realmente vai prosperar para nós. Então, neste caso, quando estamos fazendo operações localmente, podemos usar o bloqueio para garantir que nossas operações serão consistentes e que não encontramos nenhuma condição de corrida. E então, realmente, novamente, o ponto de limitação vai ser mais para E/S de rede. Então, obviamente, apenas estar ciente dos efeitos de que você terá quando você usar bloqueio. Mas vamos em frente e ver isso em ação. Então o que vamos fazer toda vez antes de incrementar o valor, porque vamos dizer bloqueio adquirir. E depois vamos liberar esta fechadura. Então vamos em frente e executar isso mais uma vez. E lá vamos nós, obtemos o resultado esperado. Agora. Então, há um método que eu, que eu recomendaria usar aqui embora eu acho que é um pouco mais limpo, em seguida, bloquear que adquirir, bloquear e liberar. Porque quando você chama aquisição, você só tem que lembrar de também chamar liberação. Caso contrário, você vai começar a ter problemas. Então vamos ver isso em pequena escala. E vamos comandar isto. Tudo bem. Estou terminando uma vez porque não vamos liberar a fechadura. Então, basicamente adquirimos uma fechadura e nada mais pode correr até que esta fechadura seja liberada por alguma coisa. Então, vou interromper isto. Então, obviamente, não queremos esquecer isso. Então, a maneira mais fácil que podemos fazer isso dentro do Python é usando o Gerenciador de Contexto. Então o que podemos dizer é, em vez disso , com Locke, vamos incrementar o contador em um. Então o que isso faz é tudo dentro deste travessão aqui. Então, bata na porta. E você está trancando. Tudo dentro deste recuo aqui vai estar dentro do bloco de pontos de aquisição e, em seguida, bloqueada liberação. Assim que sairmos deste recuo, onde essencialmente chamando aqui loc dot release. E no início deste nnd, vamos chamar a aquisição do laptop. Mas este caminho é obviamente um pouco mais limpo porque não temos que chamar o lançamento real. Não temos que nos certificar de que não os esqueçamos porque isso pode ser problemático, especialmente se você tiver programas que vão ser executados por algum tempo. E você leva um bom tempo para descobrir que você realmente esqueceu de soltar a fechadura. Então, em vez disso, podemos apenas usar o gerenciador de contexto e dizer com bloqueio. E então tudo aqui vai ser entre essa fechadura que adquiriu no início e trancada ou pelo menos no final. E não precisamos nos preocupar em esquecer que esquecemos de soltar a fechadura. E assim podemos ver que também voltamos para o dez para o seis que estávamos em quatro. Aqui, devemos também obter a fórmula que estávamos esperando. Portanto, esta é apenas uma coisa importante a ter em mente, porque anteriormente estávamos usando filas para tudo o que é seguro para threads. Mas, às vezes, se você fizer outras coisas, especialmente se você estiver acessando variáveis compartilhadas, então pode haver problemas lá. Então pense em como seu programa está interagindo. E se você precisa usar fechaduras e se você sabe que está neles. Se você escreveu um programa onde potencialmente você pode realmente encontrar uma condição de corrida, basta ter em mente que o bloqueio vai ser uma ferramenta importante para usar lá para garantir que você realmente obter os resultados corretos Estou esperando. 16. Introdução ao Multiprocessamento: Tudo bem, então agora que vimos uma boa quantidade de coisas sobre rosqueamento, vamos em frente e dar uma olhada no multiprocessamento. Agora, primeiro eu só quero escrever um script de encadeamento simples novamente. E então eu realmente já tenho meu monitor de atividade aberto para que possamos monitorar ou usar a CPU um pouco. E então vamos ver como isso muda quando vamos para o multiprocessamento. Então eu vou dizer a partir de um threading, Eu vou importar thread. Nós vamos ter uma função aqui que ele só vai dizer verificar valores na lista. E vai levar em algumas listas, vamos chamar isso de x. e o que ele vai fazer aqui é que vai ter um loop. Nós diremos para mim no alcance. E vamos fazer dez para o poder de oito, então 100 milhões. E tudo o que vamos fazer é verificar se eu é um X. E então vamos criar alguns tópicos. Então nós vamos dizer número de tópicos vai ser quatro. E teremos nossa lista de tópicos aqui. Vamos manter o controle disso. E eu vou dizer para eu na faixa número de threads, vamos criar o segmento. Nós vamos tê-lo. A função de destino é este valor de verificação na lista. E os argumentos que vamos fornecer a ele vai ser a lista que queremos usar. Então, vamos dizer lista de comparação. Vai ser igual a 1, 2, 3. Forneça isso como entrada. Então o que vamos fazer é apenas verificar quatro segmentos diferentes em loop sobre 100 milhões de valores para ver se algum desses valores está dentro deste segmento. Então, basicamente, apenas fazendo algumas operações de CPU sem quaisquer componentes de rede. E, claro, queremos acrescentar esses tópicos à nossa lista onde os acompanhamos. E eu vou dizer para tn threads, nós vamos começar nossos threads e vamos dizer para 10 threads, então nós também vamos juntar-se ou ameaças. E vamos também importar o tempo aqui. E logo antes de começarmos, diremos que a hora de início é cronometrada. E então diremos que tudo levou. Vamos fazer time.DeltaMe menos tempo de início, segundos. Ok, então o que nós fizemos aqui é apenas um programa básico de threading. Começamos e juntamos nossos tópicos, é claro, como cobrimos muito recentemente. E nós apenas temos a lista simples que contém três valores e para quatro segmentos diferentes, nós estamos indo apenas para em cada loop thread sobre. Então nós vamos estar fazendo um monte de repetição, repetição de operações, na verdade, para cada uma dessas, nós vamos apenas verificar se o valor está dentro de lá. E então vamos cronometrar toda essa operação para ver quanto tempo tudo isso leva. Então eu vou apenas começar a nossa principal função aqui. E se formos ao nosso monitor de atividade, então podemos ver que haverá, claro, um pequeno pico, que é o que esperaríamos. Porque obviamente algo vai funcionar. Nós podemos realmente ver o nosso processo Python aqui estão agora apenas fazendo o trabalho. E vai levar um pouco de tempo para, você sabe, terminar tudo isso. Mas espero que termine logo. Tudo bem, então levou cerca de 33 segundos e podemos ver que nossa CPU é uma alegria, não super significativa, é claro, um pouco obviamente acima dos valores padrão que temos, mas podemos ver em geral quanto tempo demorou. Então, é claro, porque nós não temos realmente nenhum componente de rede, muitas dessas coisas estão acontecendo um após o outro, hum, porque nós realmente não estamos tendo nenhum componente de rede esperando. Então, agora vamos, em vez de usar o threading, vamos em frente e usar o multiprocessamento. Então, vamos dizer a partir de multiprocessamento, vamos importar classe processo. Agora, a coisa boa sobre o processamento e a biblioteca multiprocessamento é que ele é realmente muito, muito semelhante em termos de como ele é escrito para a biblioteca de threading. Então, embora nós temos que fazer realmente é apenas mudar esses nomes realmente para legibilidade. A única coisa que tivemos que mudar foi essa coisa aqui. E agora vamos usar multiprocessamento em vez disso. Então o que nós vamos fazer é nós vamos, e vamos atualizar isso para ele não é mais números threads, é número de processos. Vamos criar quatro processos separados. Então vamos começar como fizemos antes. Vamos esperar que terminem como fizemos antes. Estamos a fornecer os argumentos aqui, tal como fizemos antes. E a função que estamos chamando também não mudou. Então estamos basicamente fazendo exatamente a mesma coisa, mas agora estamos usando multiprocessamento. Então vamos em frente e executar isso. E eu vou abrir aqui o nosso monitor de atividades. E agora, de repente, você pode vê-lo aumentar. E, em seguida, um segundo aqui, nós vamos ter quatro processos. E então esse é o número de processos que realmente criamos em execução. Então o que acontece neste caso é que estamos realmente fazendo uso de mais de um núcleo. Então eu tenho mais de um núcleo disponível na minha máquina. E então, por causa disso, podemos fazer mais uso dela. Agora, obviamente, como podemos ver aqui, são speedup não é exatamente proporcional. Há alguns outros fatores acontecendo. Então, uma das coisas que você teria visto é que a utilização da CPU para os quatro processos não era a mesma que a utilização da CPU que um dos processos tinha. Então eu acho que, além de monitorar isso, ele disse cerca de 80% para cada um dos processos, enquanto que a ameaça na verdade quase 99. Alguma coisa. Uma utilização muito maior nesse sentido. Obviamente precisamos deixar espaço para outras coisas acontecendo também, e nosso sistema operacional, geralmente cuidamos disso, mas podemos ver que ainda temos uma melhoria de velocidade. E a quantidade de melhoria de velocidade que podemos obter daqui depende muito do número de núcleos disponíveis em nossa máquina. Então, quanto mais núcleos tivermos, mais processos podemos criar muitos processos, mas quanto mais processos podemos executar simultaneamente, porque podemos executar cada um deles em um núcleo diferente. E então isso é realmente o que está acontecendo neste caso, é cada vez que criamos e iniciamos esse processo, estamos pegando esse interpretador Python e estamos basicamente começando uma versão semi nova em outro processo para que eles não sejam conflitante e que não há bloqueio intérprete global acontecendo. Portanto, estes não são mais dificultados entre este bloqueio intérprete global. E então o benefício que obtemos com isso é a aceleração. Agora, como falamos no início, o threading é o que vamos usá-lo para muito limitado pela E/S de rede. Considerando que o multiprocessamento é o que queremos fazer para limitado pela utilização da CPU ou processos intensivos da CPU, que neste caso não há rede ou espera ou qualquer coisa. É apenas a utilização da CPU, verificando se um valor está dentro de uma lista. E assim, a partir disso podemos ver, obviamente, nós vamos estar gerando um pouco melhores resultados de nosso multiprocessamento. 17. Multiprocessamento em filas: Então, obviamente, podemos melhorar a maneira que estamos fazendo nosso programa aqui ao invés de refazer a mesma carga de trabalho, algo que geralmente seria mais adequado para a função de multiprocessamento seria dividir nossa carga de trabalho em diferentes segmentos. Então, digamos que, em vez de refazer a mesma coisa para diferentes épocas, nós só queremos tipo de distribuir nossa carga de trabalho. Então vamos ter alguns parâmetros extras aqui. Isso vai ser o nosso, nós vamos chamá-lo de AI agora e, e então nós vamos ter um número total de processos. Então o que vamos fazer aqui é basicamente fazer uso do olho dela e do nosso número total de processos para dividir isso em baldes de tamanho igual. Então nós vamos começar com basicamente ter um limite inferior, que vai ser I vezes 10 para o 8. E então nós também queremos ter um limite superior que vai ser desligado. Nós nem precisamos do número total de processos aqui, que vai ser I mais um vezes 10 para o 8. E podemos até tirar esse valor, extraído um abstraído para outra variável. Então, vamos dizer que o número máximo para verificar dois vai ser dez para o oitavo. E então vamos começar do nosso limite inferior. Vamos para o nosso limite superior. Então, vamos dizer de eu na faixa de baixo para cima. E então, por exemplo, se tivermos 0 aqui, vamos de 0 a basicamente, bem, uma vez isso. Então precisamos de uma série de processos. Foi aí que entrou. Número de processos. E nós vamos apenas dividir isso aqui pelo número de processos e converter tudo isso em um inteiro. Uma vez que a nossa função de intervalo aqui quires que usamos um inteiro. Então nós vamos ir de, o primeiro passo vai ser de 0 a uma vezes esse número dividido pelo número de processos. Então vai ser 1 sobre 4 sobre 10 milhões de 100 milhões, que vai ser 25 milhões. E, em seguida, quando eu for um, vamos de 25 milhões para 50 milhões. Então vai ser 2 vezes 25 milhões. E então nós vamos e esses passos. Certo, então o olho que já temos aqui, eu sou do nosso olho aqui, o número de processos que você também tem, porque é isso que estamos definindo neste loop de intervalo aqui. Então o que estamos fazendo neste caso é, bem, agora nós apenas reescrevemos para torná-lo um programa pelo menos semi realista para entender ou ver como podemos dividir a carga de trabalho. E se rodarmos isso novamente, então, obviamente, em nosso monitoramento de atividade ou segundo, vamos ver sua carga de CPU, carregar aqui pico. Mas obviamente vai ser muito mais curto porque não estamos fazendo a mesma coisa quatro vezes, mas em vez disso, se dividirmos esta operação em quatro processos separados. Então sim, Então geralmente Embora, nós não queremos apenas ter essa informação, mas também queremos usá-la. E então vimos anteriormente muita coisa que podemos realmente usar a fila para passar informações. E podemos fazer uma coisa semelhante aqui. Nós ainda pode usar nossa fila e podemos criar uma instância da classe fora. E também podemos fornecer isso como entrada, como temos aqui. E então talvez a informação que queremos transmitir é cada bucket, quantos valores estão em nossa lista e quantos valores não estão em nossa lista. Então vamos ter uma variável que tem o número de hits, apenas vai ser 0. E então nós vamos apenas dizer se x, vamos incrementar ou número de hits por um. E então, no final, vamos colocar esse valor na fila junto com inferior, superior e um número de hits. Assim, podemos fazer algum processamento. Podemos realmente fazer uso da informação dos resultados que estamos processando. Então, vamos apenas verificar em cada intervalo de bucket quantas de nossas variáveis estão realmente dentro desta lista. Vamos colocar isso em uma fila. E então aqui no final, nós também queremos apenas colocar feito na fila. E então nós vamos ter apenas um loop enquanto simples que vai dizer enquanto. E então vamos dizer que v é igual a Q ponto recebe. Se v é igual a feito, nós vamos sair. Caso contrário, temos o nosso número inferior ou superior de acertos e Veeam. E nós vamos dizer entre inferior e superior, nós temos o número de acertos valores na lista. Tudo bem, então vamos fazer isso mais uma vez. E novamente em nosso gráfico de CPU, podemos ver o pequeno pico aqui. Então podemos ver agora que temos algumas boas informações. Então, entre, neste caso, 0 a 25 milhões, temos três valores na lista, obviamente, porque temos 123 na lista. E entre os outros, não temos muita informação. Então o ponto desta lição é que podemos ver ainda podemos continuar a usar Q da mesma forma que você usou antes, mas sendo capaz de passar informações entre e processos ou segmentos diferentes como fizemos antes. Mas agora vai ser entre diferentes processos e usar isso lá dentro. E esperançosamente, você pode ver que podemos usar processos para basicamente espalhar a carga de trabalho. Obviamente, o exemplo que temos aqui é um exemplo muito simplificado. Mas ainda podemos economizar uma quantidade decente de tempo ao invés de usar a execução em série fazendo tudo ao mesmo tempo. Ou mesmo encadeamento onde basicamente vai ser a mesma coisa, porque nós somos tão intensivos em CPU, conseguimos fazer mais uso do número de núcleos que temos disponíveis em nossa máquina. E, na verdade, fazer uso de mais de nossa CPU para nos ajudar a concluir esses cálculos mais rapidamente. Agora, isso é importante para um, se você está executando coisas em sua própria máquina, só queria terminar mais rápido e você tem muitos recursos que estão apenas ociosos. Isso pode obviamente ajudá-lo a falar de programas, mas também se você estiver implantando aplicativos e tiver recursos extras de CPU disponíveis, se você não estiver fazendo uso desses recursos, eles vão ficar ociosos e você vai pagar eles, mas você não vai realmente estar fazendo uso deles. Então, obviamente, isso depende, você sabe, se você tem um único núcleo em qualquer coisa que você está implantando, então esse multiprocessamento não vai ajudar muito, porque você ainda tem apenas um núcleo disponível. Mas se você acabar por ter uma máquina ou ter uma implantação onde você tem vários núcleos de CPU disponíveis. Você quer ter certeza de que você pode fazer o melhor uso deles. 18. Multiprocessamento em conjunto de processamento: Tudo bem, então, até agora nós vimos como podemos usar o multiprocessamento para nos ajudar a distribuir parte do nosso trabalho em diferentes CPUs. E, obviamente, o padrão que estamos vendo aqui é muito semelhante ao padrão de rosqueamento que tínhamos entrado em detalhes anteriormente. E você provavelmente já pode adivinhar. Mas a maneira como fizemos herança de classe com threading e tudo o que fizemos quando criamos nossos workers de threading, podemos fazer a mesma coisa com a classe de processo. Então, podemos herdar da classe de processo e podemos ter um início e junção métodos definidos dentro, bem como seus métodos de execução. E nós podemos basicamente abordar a criação de um programa multi-processamento em torno de classes multiprocessamento que todos inibem e herdam desta classe de processo, assim como fizemos quando passamos por todas as coisas de threading. E não vamos descer por esse caminho porque já fizemos isso para roscar. E, obviamente, haveria um monte de coisas repetidas que estaríamos indo para baixo. Portanto, apenas esteja ciente de que o que fizemos para encadeamento e as abordagens que usamos na sintaxe será quase idêntico ao multiprocessamento, exceto que em vez de usar a classe thread, você estará usando o processo classe aqui. Então o que eu quero mostrar agora, porém, é às vezes quando escrevemos um programa de threading, anteriormente havia um monte de E/S de rede e pode fazer sentido ter estes como intrincadamente desenvolver programas para que possamos usar dicas para passar todos os estado internamente. E enquanto um threads diferentes são responsáveis por diferentes serviços que todo o tipo de lidar com a carga de rede lá. Mas às vezes, quando estamos fazendo multiprocessamento, nós meio que temos nosso fluxo de trabalho cortado e em vez de reescrever tudo, nós apenas sabemos, oh, aqui está algo que eu quero otimizar. E, obviamente, podemos fazer a mesma coisa com threading se tivermos como um pequeno componente onde estamos tipo, oh, aqui está um monte de coisas de rede que eu basicamente posso otimizar e você sabe, em vez de esperar e serializado, Eu posso apenas fazer todas essas coisas e basicamente metade de todos os tópicos para que a espera aconteça quase simultaneamente. Mas para o processamento agora eu só quero tipo de foco nesse componente. E em vez de gerar processos individuais como este, usando filas para passar informações, eu só quero simplificar muito essa coisa. E o que eu quero fazer em vez disso é que eu quero chegar ao ponto em que eu possa simplesmente passar nossos limites inferior e superior. E basicamente tipo de apenas distribuiu este trabalho para nós e então apenas obter como um centro de valor de retorno. Pegue o Q aqui fora para tirar este Q. Então eu não quero usar dicas ou algo assim. Basicamente, eu só quero ter uma variável que eu possa ter como uma variável de resultado que vai dizer algo como 30, 0, 0, e para que eu possa continuar usando isso. Agora, antes de fazermos isso, vamos começar com algo mais simples. Nós vamos apenas começar com o pool de processamento básico e nós vamos ter uma função muito mais simples onde nós estamos apenas indo para quadrado tudo. Então nós vamos voltar muito ao básico, volta a um tipo de exemplos muito mais simples. E nós vamos apenas ter uma função simples primeiro que nos permite quadrar tudo. Porque, em última análise, uma vez que podemos fazer isso, podemos então fazer coisas mais complicadas na sintaxe, ponto difere um pouco de como estamos usando o pool, é por isso que eu quero começar com este exemplo muito simples primeiro para que podemos ver como isso funciona e como podemos obter esse resultado. Então podemos ir sobre atualização ou sintaxe para que possamos fazer o ainda não super complicado, mas obviamente passando mais variáveis e coisas que tínhamos antes. Então, em vez de usar o processo, vamos agora usar a classe de piscina. Agora com a classe pool, podemos inicializá-lo usando o contexto. Então, com piscina como piscina ou como P ou o que você quer puxa muito bom porque, você sabe, obviamente é bastante específico. Podemos ser mais específicos e dizer como multiprocessamento. Tenho certeza que há um erro de digitação aqui em algum lugar. Pool de processamento. Ou se não quisermos escrever tudo assim, podemos escrever como e as pessoas serem um pouco mais específicas. Mas basicamente vamos inicializar essa classe de pool e, em seguida, usá-la dentro do contexto. Então agora temos à nossa disposição um conjunto de processos que podemos usar. Então, basicamente, e vamos entrar nisso em um segundo. Mas podemos realmente definir aqui o número de processos que queremos ter disponíveis em nosso pool. Por exemplo, quem colocou o número dois? E aqui, isso significa que temos o potencial, mas não precisamos necessariamente usá-lo de dois processos que estão disponíveis para nós e podemos continuar realizando operações e basicamente tomando esses processos. Mas uma vez que todos esses processos são removidos do pool, eles não estão mais disponíveis para nós e basicamente temos que esperar até que o processo seja retornado ao pool para que a próxima operação possa usá-lo. Então novamente conosco, nós basicamente, eles vão criar como um pequeno, você pode imaginar como um pequeno balde. E nesse balde temos uma série de itens disponíveis. E podemos tirar daquele balde. E uma vez que o balde está vazio, temos que esperar até, você sabe, algo, alguém colocar o item que eles levaram de volta. E quando algo estiver no balde de novo, podemos tirá-lo de volta. Então agora temos um pool de tamanho dois, que significa que temos dois processos disponíveis para nós que podemos usar, que significa essencialmente que podemos usar para o curso, já que cada processo vai gerar um novo núcleo. Então o que vamos fazer aqui é usar um novo método. Vamos usar o nosso multiprocessamento legal. E nele vamos usar este método de mapa. E aqui vamos colocar a função que queremos usar. Então essa vai ser a praça. E então nós também vamos fornecer nossas variáveis de entrada aqui. E vamos salvar tudo isso em uma variável de resultado. E podemos tirar o componente de tempo aqui, já que não estamos mais usando isso. E vamos em frente e imprimir o nosso resultado. Isto não pode simplesmente executar a nossa função principal. Está bem? Então, basicamente, temos exatamente o que esperávamos, que é pegamos nossa lista de entrada aqui e temos o quadrado de cada valor. Mas agora a coisa interessante que temos conosco é que somos capazes de usar este pool e nós somos capazes de aplicar esse método de mapa lá. E nós estamos indo, basicamente vai aplicar isso a cada componente. Então ele vai ser iterando através daqueles um por um. Mas vamos ter a mesma estrutura de volta, mas com nossos valores atualizados internamente, mesmo que estejamos apenas operando em uma variável, podemos retornar isso e basicamente obter nosso novo resultado, que será nossa lista original aqui em nossas listas de comparação neste momento. Mas vai ser ao quadrado. Então, cada valor aqui vai ser quadrado. Agora, esse valor, obviamente, pode depender da máquina que você está ficando sem. Às vezes, você só pode usar uma CPU porque você só tem uma disponível. Às vezes você pode quatro ou seis ou oito ou 16 ou quantos você tem disponível em sua máquina. Então, como podemos fazer isso um pouco melhor para que ele possa realmente se adaptar à máquina em que está rodando? Bem, há uma função legal que podemos importar chamada de contagem de CPU. E a contagem de CPU, como você deve ter adivinhado, ele, vai apenas nos dar o número de CPUs que temos disponíveis. Então o que você pode fazer é dizer o número de CPUs disponíveis. Só vai ser, e nós vamos apenas invocar nossa contagem de CPU. Então, por apenas imprimir isso. E você pode ver minha máquina que vai atirar para já que eu tenho quatro carbonos disponíveis. Mas isso pode ser diferente dependendo da máquina em que você está executando. Mas talvez o número de CPUs que você deseja usar seja um a menos do que o número de CPUs disponíveis. Porque se você está usando todos os seus núcleos, então há, você sabe, tudo vai ser usado. E, portanto, pode não haver CPUs suficientes para outras coisas continuarem. Outros processos do sistema operacional, por exemplo. Então, geralmente o que você quer fazer é que você pode dizer que o número de CPUs a usar será nossa contagem de CPU menos um. Mas no caso em que só temos um núcleo, queremos dizer, tudo bem, bem, vai ser o mínimo. Então eu só vou ser pensado o máximo entre um e o número de CPUs disponíveis menos1. E então podemos usar isso aqui. Então, neste caso, por exemplo, eu posso imprimir o número de CPUs usadas. E agora vamos mostrar três, já que vai ser o valor máximo entre 14 menos um, que é três. Então o valor máximo entre estes dois vai ser três. Mas no caso em que só temos uma CPU, então estamos, esse valor é um. Em vez disso, vamos usar o padrão. Já que, obviamente, ainda queríamos fazer alguma coisa. Então, desta forma, podemos dizer, tudo bem, então dependendo da máquina em que estamos rodando, podemos ver o número de CPUs disponíveis. E então nós podemos ter nosso pool ser desse tamanho, que muitos números de processos estão disponíveis para nós extrair. E então podemos mapear sobre esses objetos de entrada para a função que queremos usar para isso e, em seguida, obter aqueles apenas realmente bom valor de retorno que podemos apenas continuar usando. Então, em vez de ter que fazer este cereal. Então nós estamos iterando e nós estamos dizendo k para I na faixa de qualquer longa ou lista é. E então vamos para a praça e vamos colocar isso em uma nova lista. Nós vamos, nós vamos atualizar nosso valor, qualquer um, e então continuar usando assim. Podemos apenas usar este pool multiprocessamento e basicamente mapear esses valores em nossa função e apenas obter os valores de retorno atualizados para que possamos continuar usando isso. Porque estas, estas disfunções podem acontecer em paralelo porque obviamente não depende de mais nada ao seu redor. E assim, com isso, somos capazes de dimensionar, usar isso para rapidamente acelerar certas partes do nosso código que não precisam necessariamente de uma refatoração completa, como a maneira que vimos com o threading. Mas você sabe, apenas uma pequena linha aqui poderia realmente nos ajudar a distribuir muito do trabalho. E então podemos continuar da nossa maneira regular. 19. Multiprocessamento em conjunto mapa de conjuntos múltiplo de argumentos: Tudo bem, então agora você provavelmente vai estar se perguntando, ok, bem, como eu posso passar vários argumentos? Como posso fazer algo assim? E eu quero fazer x, mas eu quero fazer x para o poder de y assim. E eu quero dizer, você sabe, nosso novo valor de poder será de três. Você pode ter pensado isso. Eu só vou colocar esse argumento extra aqui e isso vai cuidar disso. Infelizmente, não. E eu vou te mostrar o que vai acontecer, mas eu tenho que desfazer isso. Caso contrário, vamos ter um problema diferente aqui. Mas se executarmos isso e olharmos para a saída, não estamos mais passando os valores individuais dentro da lista aqui, mas estamos passando a própria lista. Então estamos iterando sobre cada elemento aqui e passando isso como entrada. Então, se nós colocarmos y aqui, nós não vamos obter os resultados que queremos, independentemente de se nós o tivermos. E veja aqui, ainda estamos chamando, não estamos imprimindo porque nossa função já está falhando porque estamos perdendo um argumento adicional para o porquê. E mesmo que façamos algo assim, nenhum deles vai funcionar para nós. Então, como podemos fornecer este parâmetro extra aqui? Bem, vamos usar um pacote Python chamado ferramentas func, que já vem pré-instalado com Python. E a partir daqui vamos importar um método chamado parcial. Agora parcial vai nos permitir criar funções parcialmente definidas. Podemos ligar parcialmente para eles, mas eles não serão totalmente chamados. Mas já podemos nos fornecer alguns dos parâmetros antemão e então podemos perdê-lo mais tarde. Agora, para fazer isso, porque a maneira que vamos fornecer parâmetros vai estar em uma ordem específica. E então queremos ter certeza de que deixamos o parâmetro que vai ser basicamente a variável que vai mudar até o final. Então eu vou criar uma função parcial usando o método parcial. Vou ter esta praça aqui. E o valor que quero para ti será o nosso poder aqui. Agora eu posso usar essa função parcial no método do mapa e eu posso tirar todas essas coisas embora. Agora nosso mapa vai apenas iterar sobre este um por um, e ele vai chamar esta função aqui. Esta função já está parcialmente definida chamando tomando o método raiz quadrada e fornecendo este primeiro parâmetro, poder como este. Então, se fizermos isso agora, vamos colocar tudo em cubos, já que é isso que temos aqui. Obviamente, podemos mudar tudo para o poder dos quatro, como temos aqui. E também podemos estender isso para parâmetros extras como adição, componente. E digamos que queremos ter tudo ao Poder das Três. E então queremos ter algum componente adicional, e isso vai ser 2. Vamos providenciar isso aqui. Então nós vamos apenas adicionar isso ao resultado no final. Então, se eu executar isso, então nós vamos obter tudo em cubo e então nós vamos ter um mais dois que vem deste erro de digitação aqui. Então, podemos ver se queremos usar o método do mapa e queremos ter variáveis extras aqui. Nós não podemos simplesmente transformar isso em uma tupla ou uma lista e então pensar que, Oh sim, tudo vai rolar sobre isso. Infelizmente, não é assim que o método de mapa funciona com pool multiprocessamento. Mas se temos variáveis fixas que já definimos de antemão que só queremos fornecer aqui. E o nosso último componente aqui vai ser a coisa que vai mudar. Então podemos realmente usar este método parcial a partir das ferramentas funk. E aqui podemos definir parcialmente nossa função. E então podemos preenchê-lo com os diferentes componentes que temos aqui para tipo de chamar a função e é maneira completa e realmente obter os resultados que queremos enquanto já tendo alguns dos argumentos passados. 20. Multiprocessamento de múltiplos argumentos variando: Muito bem, então anteriormente vimos que poderíamos fornecer argumentos adicionais usando este método parcial em nossas ferramentas func, uma biblioteca aqui que importamos. E fomos capazes de definir parcialmente funções ou fornecer parcialmente os componentes das funções. E então podemos usar nosso método de mapa aqui para tipo de fornecer esse componente restante. Mas e se não quisermos ou não temos componentes fixos, mas em vez disso queremos ter alguma entidade diferente, por exemplo, alguns impotentes. E aqui o que queremos fazer é que queremos ter o primeiro elemento aqui, por exemplo, o poder para o segundo para o poder 5 e o terceiro para o poder de seis. Portanto, já sabemos o que queremos fornecer. Como podemos fazer isso de uma maneira que não é assim, mas idealmente apenas ser capaz de fornecer isso diretamente e realizar esses cálculos. Então eu vou fazer alguma limpeza rápida aqui em cima, remover essas coisas, e também fazer apenas uma reorganização de nossos parâmetros de função. Só ter um pouco mais deve ser mentir. Um pouco mais fácil de ver. E também não precisamos dessa definição de função parcial aqui. Então o que queremos fazer é, ou o que podemos fazer é usar um método chamado mapa estelar. Agora em nosso mapa estelar, podemos fornecer uma entrada aqui que tem o seguinte, que se parece com isso. E então dentro podemos fornecer elementos adicionais que podemos repetir se quisermos. E todos esses elementos, podemos então passar como parâmetros individuais para nossa função. Então, por exemplo, no nosso caso, o que queríamos fazer é enquanto um primeiro elemento que queremos passar seria 1 e 4, já que isso vai ser nosso x e y. o segundo vai ser 25, e então o terceiro aqui é vai ser 36, uma vez que queremos fornecer estes dois juntos e, em seguida, fornecê-los como nosso x e nossos parâmetros y. E então, se nós fornecermos isso como entrada, então basicamente o que nós vamos obter é a execução como esta. E, obviamente, estamos usando quem o pool de multiprocessamento ainda. Então vamos ser capazes de usar cores diferentes para nos ajudar a fazer isso. Então o que realmente precisamos fazer agora é juntar essas duas listas de uma forma que possamos obter esse formato aqui. E então podemos fornecer isso como uma entrada. Então nós vamos ter a nossa lista preparada, que vai ser apenas lista vazia que vamos começar com. Então vamos apenas iterar ao longo do comprimento desta lista. E assim nossos elementos que queremos adicionar aqui vai ser, queremos ter aqui, nosso primeiro elemento sempre virá da nossa lista de comparação. Vai ser o primeiro elemento aqui. E o segundo elemento que queremos, ele virá da nossa lista de energia, que podemos colocar 0. Queremos o i-ésimo componente. E assim podemos imprimir a última vez que vamos inserir algumas listas para usar como entrada. Só vai ser isto. E depois podemos comandar isto. E então nós seremos realmente capazes de fornecer cada um dos elementos dentro como um dos parâmetros aqui. Então vamos em frente e executar este loop. Tenho aqui um erro de digitação. E eu também esqueci de atualizar. Isto levanta aqui. Então vamos tentar isso mais uma vez. Lá vamos nós. Então esta é a lista que estamos usando como entrada. E podemos ver que nosso x e nosso y. Então estes são nossos parâmetros de função que estamos passando. Então este vai ser seu x e nosso y, nosso X e nosso Y, ou X e nosso Y. Então estamos fazendo um para o poder quatro, que é 12 para o poder de cinco, que deve ser 32, e 3 para o poder de seis, que deve ser 729. Então podemos ver que usando um mapa estelar, nós somos realmente capazes de fornecer vários parâmetros de entrada, especialmente se, você sabe que eles vão mudar. É importante ter certeza de que temos esse tipo de estrutura para que possamos passar isso. E então os elementos ou os valores que estamos passando para nossa função vão estar na ordem em que temos os parâmetros em nossa função aqui. E assim, através desta forma, somos realmente capazes de passar em vários parâmetros. Então o morcego, nós não precisamos usar essas definições funcionais parciais, função se mais de uma de nossas variáveis estiver variando. 21. : Tudo bem, então vamos finalmente voltar à nossa função inicial um pouco mais intensiva de CPU que estávamos usando, que será apenas verificar se um valor ou quantos valores em nossa lista de comparação estão realmente dentro de um intervalo específico. Então, pode dizer, chamar isso, por exemplo, verificar o número de valores no intervalo. E então nós vamos ter aqui vai ser a nossa lista de comparação. E aqui vamos ter os nossos limites inferior e superior. E depois queremos rastrear os números. E então nós queremos dizer para eu na faixa de baixo para o nosso limite superior. Se olhos e nossa lista aqui. Só queremos incrementar isto por um. Então, sim, estamos perdendo um I aqui e no final queremos apenas devolver o número de visitas. Então, novamente, o objetivo desta função não é realmente fazer nada mais exceto ser algo de alguma maneira, para nós tipo de simular apenas um pouco mais de uma tarefa computacionalmente intensiva porque ele vai levar um pouco de tempo para calcular isso. Então, as diferentes faixas inferior e superior que vamos ter. E se quisermos, podemos especificar essas regras de intervalo. Vamos chamar esses limites inferiores e superiores. E, claro, podemos gerar esses dois com um pequeno for-loop. Mas, na verdade, se estamos nos dividindo em quatro, basicamente você pode ver que o que estamos fazendo é que vamos de 0 a 25 milhões. Então vai ser dez para o poder de seis. E então vamos passar de 25 milhões para 50 milhões vezes dez para o poder de seis. E depois vou copiar isto. E vamos passar de 50 milhões para 75 milhões. E finalmente, queremos passar de 75 milhões para 100 milhões. Portanto, estes serão os nossos limites inferiores e superiores. Agora, é claro, precisamos colocá-lo neste tipo de formato. Mas, em vez disso, o que queremos neste caso é basicamente queremos nossas listas de comparação para o primeiro valor de entrada. E depois queremos a nossa parte inferior e a nossa parte superior aqui. E depois queríamos fazer estes ou os outros também. Então ainda precisamos fazer um pouco de união como fizemos aqui. Mas como não temos muitos valores aqui, eu sou apenas ser mais fácil de colocar esses quatro valores e à mão. Mas, obviamente, podemos escrever um pouco para loop para preencher esta lista para nós também, especialmente se você quiser como 50 ou um 100 ou mesmo como 10 ou 20 equilíbrio diferente. Sim, de qualquer forma, então só precisamos de preparar a nossa lista. Então vamos usar nossa lista de comparação aqui. Mas em vez de iterar sobre este comprimento, vamos basicamente adicionar isso como um dos elementos aqui. E assim o número de valores de entrada diferentes que vamos ter vai realmente ser as listas, o comprimento desta lista. Portanto, queremos iterar ao longo do comprimento desta lista. Aqui queremos adicionar a lista de comparação completa. E também queremos adicionar os componentes individuais. Então vai ser o nosso primeiro e segundo valor aqui. E então nós vamos fornecer isso como entrada para fazer nossos cálculos. Então, novamente, o que estamos fazendo é pegar essa lista e estamos basicamente tendo nossa nova lista preparada, que vai ficar assim e assim. Então é isso que estamos fazendo aqui. E então este componente aqui vai ser a nossa primeira entrada aqui, que vai ser uma lista. E então os outros serão nossos limites inferiores e superiores. Então eu vou desfazer isso, obviamente, porque isso é o que este pequeno loop aqui como quatro. E então vamos em frente e executar isso. E assim podemos ver que estes serão os nossos parâmetros de entrada aqui. Cada um deles, como temos nos argumentos de função, esta será nossa lista de comparação, nossos limites inferior e superior. E assim podemos ver, obviamente, no primeiro intervalo temos três elementos que estão contidos lado porque seus números são 123. E, em seguida, os outros estavam todos indo para ter 0. Então isso é meio que indo círculo completo de volta para o que começamos com quatro, desculpe, exemplo para multiprocessamento para tipo de nos ajudar a fazer isso. E agora podemos usar nosso método de inicialização neste caso para fornecer esses vários argumentos de entrada como temos aqui. Agora, uma coisa que podemos realmente fazer para simplificar um pouco a sintaxe, é em vez de listar as listas como esta. Em vez disso, o que podemos fazer é usar este pequeno asterix. E o que isso vai fazer é desempacotar todos os valores aqui. Então você pode ver se eu voltar a executar isso, nós vamos obter exatamente os mesmos resultados. A única diferença é em vez de eu ter que fazer referência a cada um desses componentes individuais como fizemos aqui. Esta estrela está basicamente indo para descompactá-lo e ele vai tomar todos estes e fornecê-los como valores de entrada adicionais um de cada vez, seguindo exatamente na ordem em que nós os temos aqui. Então esta é apenas uma pequena abreviação que eu posso usar em vez de usar isso porque eu quero obter todos os elementos. Mas se eu tiver, você sabe, 10, 20 ou 15, como se fosse ficar mais longo e vai ser entediante. E então realmente o que eu quero fazer é que eu só quero ter todos esses valores aqui, mas eu não quero eles em um formato tupla como este. Eu só quero todos os elementos individuais um após o outro. E a maneira que eu posso fazer isso é usando a estrela, que vai fornecer cada um desses elementos dentro como valores individuais aqui. Então isso é apenas uma abreviação para manter isso mais limpo e também torná-lo um pouco mais rápido para escrever. 22. Introdução ao redação ao redação de programas Asynchronous: Tudo bem, então vamos agora começar a dar uma olhada em programas assíncronos ou como podemos escrever um programa assíncrono. E esta vai ser a nossa terceira opção que temos para a simultaneidade. E você vai notar um ponto. Ele provavelmente vai parecer semelhante ao threading, embora novamente diferente porque com programas assíncronos, temos apenas um thread que está sendo executado, e nós também temos apenas um processo. Então vamos em frente e vamos ver o que acontece. Então a primeira coisa que vamos fazer é importar E/S assíncrona, que só vai nos ajudar com tudo isso. Agora eu estou no Python versão 3.7 e eu recomendo que você também está trabalhando em pelo menos Python versão 3.7. Mas também, obviamente, se você estiver em uma versão posterior do Python, será melhor só porque até este ponto, a biblioteca assíncrona tem sido um pouco não experimental, mas tem mudado muito. E neste ponto parece haver um estado definido com a forma como ele está funcionando. Então eu geralmente recomendo, certifique-se de que você está usando uma versão posterior do Python, se você quiser. Ou pelo menos Python 3.7, que é novamente o que estou usando agora. Então, podemos importar IO assíncrono e que deve ser um pacote Python padrão. E então podemos começar a definir nossa primeira função assíncrona. Então podemos fazer isso apenas tendo uma função regular. Por exemplo, se queremos ter algum tipo de função de sono onde tudo o que fazemos aqui é dormir por, digamos cinco segundos. Se, em vez disso, quisermos fazer isso de forma assíncrona, então colocaríamos na frente aqui a palavra-chave assíncrona. E então aqui, em vez de usar o tempo de espera, nós realmente usaríamos um método de sono iOS sincronizado. E falaremos um pouco mais sobre o raciocínio em apenas um segundo. Mas basicamente o que obtemos com isso, é assim que vamos definir uma função assíncrona. Agora precisamos fazer mais uma coisa aqui, que é realmente precisamos esperar esta função ou esta co-rotina é realmente o que é chamado. E realmente o que está acontecendo aqui. E todo o processo de uso de execução assíncrona e Python é, e vamos ver como fazer isso em um segundo. Mas começamos algo chamado loop de eventos. E então podemos adicionar, começar a adicionar tarefas ou agendar tarefas com este loop de eventos. E então dentro desse loop de eventos terá objetos chamados ou terá coisas chamadas de futuros. E esses futuros basicamente representam algo que ainda não voltou, mas algo virá disso. Então isso pode parecer um pouco confuso, mas geralmente o que acontece se agendar várias funções assíncronas? Cada um deles vai fornecer um futuro que em algum momento e eles vão terminar ou eles vão chegar a algum tipo de ponto de verificação. E a partir desse ponto, podemos então fazer a próxima coisa com essa co-rotina. A coisa toda que definimos aqui, é geralmente referida como uma co-rotina. E são as coisas que vamos adicionar e agendar em nossos loops de eventos. Agora, enquanto continuamos a codificar, espero que isto se torne um pouco mais intuitivo e não nos perderemos tanto em toda a sintaxe de tudo. Mas, obviamente, porque não estamos passando por coisas assíncronas, é importante apenas mencionar e falar sobre algumas dessas palavras-chave e o início, mas também como estamos continuando. Então, se quiséssemos executar isso, se nós apenas ligássemos e realmente vamos renomear isso para dormir assíncrono. Se chamássemos uma pia de dormir. Durma assim. Infelizmente, não vai funcionar. Vamos receber um erro aqui, que é basicamente relacionado a isso. Bem, por exemplo, diz que o Coubertin nunca foi esperado, que é o que temos aqui. Mas mesmo que adicionemos essa palavra-chave aguarde, ela ainda não funcionará porque não temos um loop de eventos em execução agora que está consumindo tudo isso. Além disso, não podemos usar a palavra-chave await fora de uma função que não seja assíncrona def. Então, como podemos fazer essa coisa funcionar? Como podemos fazer com que esses ossos descalços funcionem? Então vamos criar uma nova função, que vai ser nossa função principal, que também vamos definir com def assíncrono. E o que vamos fazer aqui é esperar a resposta do nosso sono assíncrono. Agora, as palavras-chave aguardam aqui porque temos esse loop de eventos e podemos ter várias co-rotina diferentes programadas lá para executar. Basicamente, o que isso aguarda palavra-chave faz é que dá controle de volta ao nosso loop de eventos para continuar com outras coisas. Então, basicamente, ele diz ao programa que neste momento estamos, estamos esperando por uma resposta e até que tenhamos essa resposta ou até que tenhamos algo aqui que precisamos continuar. Não adianta me dar todos os recursos porque não há nada que eu possa fazer até conseguir isso. Então esse é geralmente o ponto de um peso. Mas mesmo que tenhamos isto, ainda não podemos chamar o Hulk principal. Então, como você pode fazer o principal funcionar? Então, o que podemos fazer é usar este método de execução de ponto I/O assíncrono. E aqui vamos colocar a co-rotina principal que queremos executar. E isso basicamente iniciará o ciclo de eventos para nós. E ele vai começar o consumo do loop de eventos e basicamente cuidar de todo o processo para nós. Existem outros métodos. Por exemplo, você pode obter um loop de eventos em execução e você pode executar até conclusão ou essas outras coisas que são mais específicas para o loop de eventos. Mas realmente apenas usando o ponto IO assíncrono Ron vai cuidar de toda essa gestão para você e você realmente não precisa se preocupar com nenhuma das coisas de nível inferior. Então este aqui vai ser o nosso ponto de entrada. Agora, uma coisa importante a observar é que só podemos ter um loop de eventos em execução por thread. E por padrão nós só vamos estar rodando isso em um núcleo e um único segmento. Então basicamente o que isso significa é que nós vamos ter apenas uma chamada de ponto de E/S assíncrona, que vai ser o ponto de entrada para o nosso programa. E, claro, podemos envolver isso no nome se for igual a principal. Hum, então para executar o arquivo principal aqui, então nós vamos começar com pode ir para este loop de eventos. Certo, então vamos tentar isso agora. Então estamos executando o programa e tudo o que estamos fazendo é assincronamente dormir por cinco segundos. Mas, obviamente, não há muito mais acontecendo neste momento, porque só estamos fazendo uma coisa. E mesmo que estejamos devolvendo o controle do ciclo de eventos, que é o que estamos fazendo aqui. Não há mais nada em execução, não há mais nada acontecendo, então não há mais nada para continuar trabalhando durante esse tempo. Então vamos adicionar uma segunda função agora, que vai ser uma função assíncrona para imprimir Olá. E tudo o que isso vai fazer é imprimir como o nome sugere. Olá. Tudo bem, então o que acontece agora? Se agendar como aqui? E então vamos colocar algumas impressões extras aqui só para ver onde estamos no nosso programa. Então você vai dizer antes de dormir. E então podemos colocar outra impressão depois. Aqui. Só vamos estar depois de dormir. Tudo bem, então o que está acontecendo? Nós temos, bem, nós pairamos o ponto de entrada. Então estamos começando basicamente o loop de eventos e estamos começando o x ou o agendamento de sua co-rotina principal. Então entramos nesta rota principal co-rotina aqui. E agora vamos para a nossa primeira linha que vai estar aguardando a resposta desta co-rotina assíncrona de sono que temos aqui. Uma vez que entramos aqui, imprimimos antes de dormir, e então temos essa chamada de espera. Então o que acontece com a chamada de espera é a forma como a chamada não está bloqueando. Permite a execução de outras rotinas co. No entanto, ele pára a execução de ir mais para baixo nesta função. Então, e se executarmos isso, você notará que entraríamos nessa função e então ligamos antes de dormir. E depois dormimos cinco segundos. E então vamos para o depois de dormir. E só então vamos para a segunda declaração aqui. Infelizmente com isso, não podemos pular e ir para a próxima coisa. Esta espera é basicamente um ponto de interrupção em nossa co-rotina, em nossa execução do programa como especificamente nesta função estão nesta co-rotina. E é aqui que paramos momentaneamente para a execução. E basicamente diz, ou a função ou a co-rotina neste momento diz, eu não preciso de controle agora. Estou à espera de uma resposta. Sinta-se livre para continuar fazendo outras coisas. E então nosso ciclo de eventos pode continuar e fazer outras coisas. E sempre que esta função estiver pronta, ele pode dar um sinal dizendo: “ Ei, eu estou pronto para continuar. E então o controle pode ser devolvido a ele. Mas porque só temos uma co-rotina principal em execução, e dentro disso, chamamos de rotinas Cole tumoral. Todos eles ainda estão sendo executados sequencialmente e não há nenhuma corotinas sendo programadas ao mesmo tempo. Assim, quando chegarmos a esta chamada de espera aqui, podemos realmente continuar com a execução de outra co-rotina. E veremos como fazer isso na próxima seção. Há mais uma coisa que eu queria mostrar-lhe de antemão, que é como podemos retornar valores a partir disso? Então vai ser como se tivéssemos funções regulares. Então vamos renomear isso de impressão Olá para devolvê-la sozinha. E isso em vez disso vai retornar olá. E assim, para obter o resultado, assim como com uma função regular, chamamos nosso retorno Olá. Mas agora, como é uma função assíncrona, temos que esperar por ela. E uma vez que esta função é feita, em seguida, obter o valor de retorno aqui. E depois podemos imprimir isto. Então ele vai fazer exatamente a mesma coisa. É só aqui. Nós não estamos imprimindo internamente, mas em vez de retornar um valor da função como esta, e você vai notar que realmente a principal diferença para uma função regular é o assíncrono e aguarde. Então poderíamos fazer a mesma coisa aqui, assim. E isso seria apenas uma chamada de função regular. E podemos obter o valor devolvido a partir daqui como normalmente fariamos. Mas isso não podemos fazer, só podemos esperar rotinas. Então isso vai causar um erro para nós, como veremos em um segundo. E outra coisa que também não podemos fazer é que não podemos. Se removermos isso e removermos isso um peso, podemos usar uma palavra-chave await dentro de um non e não dentro de uma co-rotina. Então temos que ter essa definição assíncrona na frente para ser capaz de esperar internamente. Então não podemos usar o Await sem ter uma definição assíncrona fora dele. E se tivermos uma definição assíncrona de definição assíncrona, temos que esperar a resposta porque, caso contrário, basicamente, você está criando um objeto co-rotina aqui, mas nunca foi agendado, nunca foi afastado, então ele nunca foi realmente executado, nunca foi adicionado ao loop de eventos. Portanto, apenas esteja ciente dessas coisas que, se você estiver usando assíncrono, você sempre terá que aguardar essa resposta. E a chamada de espera aqui não está bloqueando. No entanto, ele irá parar a execução adicional da função e dar controle de volta ao loop de eventos para que outras equipes possam executar no entretanto. Então, com isso, eu sei que é um pouco confuso. A primeira vez que estamos conversando sobre tudo isso e há alguns termos estranhos surgindo. Mas como vamos passar pelas próximas palestras, espero que você tenha uma compreensão mais clara de como tudo isso funciona. E provavelmente também com o tempo, isso se tornará um pouco mais confortável para você. 23. Tarefas Asynchronous: Então a próxima coisa que vamos olhar agora é como podemos criar tarefas que são, bem, vamos ver. Então a primeira coisa que notamos da última vez é, embora estejamos usando funções assíncronas aqui, e também podemos mudar isso de volta para assíncrono def e talvez apenas retornar isso para uma declaração de saudação de impressão. Como este. Acabamos de imprimir “olá” e “tunelamento”. Mesmo que estejamos usando essa sintaxe assíncrona, a execução que estamos recebendo ainda é essencialmente síncrona porque não há nada mais para o qual, você sabe, o controle possa passar. Então, embora estejamos usando essa sintaxe assíncrona e nosso controle está sendo devolvido ao loop de eventos. Não há nada mais programado que possa continuar. E então não há mais nada que possa ser trabalhado enquanto esperamos uma resposta. Da mesma forma, se tivéssemos outra chamada de sono aqui, bem, observe que nós ainda, ainda temos essa execução síncrona de reciclagem que vai começar a dormir, dormir por cinco segundos. E depois vamos para o próximo ponto. E aqui estamos nós para dormir. Vamos esperar a resposta aqui. E então, embora a execução tenha sido devolvida, não há mais nada que possa continuar. E neste ponto, embora a execução seja devolvida ao loop de eventos, novamente, não há nada que possa ser continuado porque a única coisa que não pode continuar a execução deste bloco de função, porque nós estamos ainda aguardando essa resposta aqui. E não há mais nada que está programado como que possa ser trabalhado. Então, geralmente o que podemos ter, é que podemos realmente começar a criar tarefas. Assim, podemos ter várias tarefas em nosso loop de eventos que podem ser trabalhadas enquanto as coisas estão sendo aguardadas. Então vamos ver um exemplo disso. Vamos criar uma tarefa. E vamos fazer isso entrando em um painel de pia. E nós vamos chamar aqui criar tarefa. E eu vou atender esta segunda chamada assíncrona de sono. E eu vou adicionar a tarefa e aqui. E depois vou esperar a tarefa mais tarde. Então, o que acontece quando criamos uma tarefa é basicamente programar essa co-rotina para ser trabalhada sempre que for conveniente. Mas até esperarmos, não há como parar no fluxo da nossa co-rotina para parar nesse ponto. Então, o que temos neste momento é lembrar antes de termos nossos dois sonhos que estão acontecendo um após o outro. Nesse caso, adicionamos outra tarefa. E então se nós realmente reexecutar isso, vamos ver agora que temos dois antes de dormir que estão acontecendo. E então, oops, eu tenho um erro de sintaxe aqui. Eu tenho que tirar a chamada de função porque é um objeto que estamos esperando, não uma função ou um método de co-working, porque nós já meio que chamamos a função. Então só temos um treinador, um objeto que vai voltar para nós. Mas de qualquer forma, ainda estamos esperando por isso. Mas notaremos aqui que agora estamos dormindo uma vez e agora estamos dormindo de novo. E então basicamente estamos começando isso duas vezes e então estamos no período de tempo limite, e então estamos atrás de nosso sono. Então, se importarmos o módulo de tempo, enquanto antes de estarmos executando, ele ainda é sequencialmente. Então, podemos ter uma hora de início aqui, que vai ser o nosso tempo. DeltaTatime. Podemos imprimir aqui. O tempo total vai ser tempo, tempo menos início. Então notaremos que nossa execução agora não será em torno da marca de 10 segundos, que é o que tivemos quando estávamos dormindo duas vezes seguidas, mas sim na marca de 5 segundos. Então criamos essa tarefa extra. Então, quando entramos na chamada de espera, agora temos outra co-rotina que podemos passar para onde outra tarefa que também pode ser executada. Então, neste caso, estamos tendo duas coisas sendo executadas ao mesmo tempo em que eu estou, onde o controle pode ser devolvido ao loop de eventos. E as coisas estão agendadas para serem executadas de forma assíncrona, mas essencialmente simultaneamente. Então, se adicionarmos apenas um número extra aqui e que possamos imprimir para entender, você sabe, onde estamos em cada um. Nós imprimimos n aqui, e nós imprimimos n aqui, e então aqui nós queremos adicionar um. Esta vai ser a tarefa que criamos e programamos. E então aqui podemos adicionar dois. Então, se executarmos isso, podemos ver que, bem, primeiro, estamos remarcando essa tarefa, mas então estamos aguardando essa ligação aqui, que depois chega a isso. E é aqui que a nossa execução aqui pára porque estamos aguardando a resposta aqui. Então nós demos o controle de volta para o loop de eventos. E agora temos outra tarefa que foi agendada. E agora como um momento conveniente para trabalhar nisso porque nada mais está sendo trabalhado. E então esta tarefa é agora basicamente como podemos ver aqui, começando a ser executada assim que chegarmos a este ponto de espera aqui. E então nós terminamos, ou então nosso primeiro Coubertin aqui termina. Podemos ver que a execução volta a essa co-rotina depois de entrarmos neste passo aqui. E então aguardamos o resultado desta tarefa aqui. E agora, basicamente, não estamos mais executando esse bloco de co-rotina até que tenhamos a resposta aqui, é por isso que temos essa chamada aqui. E depois avaliamos a resposta disso, é por isso que temos o “olá” aqui. Se invertermos a ordem de execução aqui, você vai notar que a ordem que temos imprimir lá fora também são mudança terá o Olá segundo último, e então teremos o depois de dormir depois disso por causa do ordem das declarações de espera aqui. Então podemos ver agora que estamos entrando nessa natureza mais simultânea porque agora temos várias rotinas de co diferentes que estão sendo executadas ao mesmo tempo. Neste caso, é muito. Mas como você sabe, uma co-rotina é meio que no lugar de apenas esperar por um resultado e ele devolve o controle para o loop de eventos. Ele pode realmente continuar e você pode começar a trabalhar em outras tarefas até que eles são ele atinge este ponto de espera. E então, uma vez que outra co-rotina tenha terminado, execução ou o controle da execução será devolvido a essa co-rotina. 24. Método de coleta de Async: Certo, então agora vimos nosso primeiro exemplo de como temos essa execução simultânea por ter tarefas agendadas. E enquanto uma co-rotina está basicamente aguardando uma resposta, a execução de outra pode continuar, que é o que tivemos quando agendamos uma tarefa aqui. E então a execução de uma espécie de aconteceu quando era conveniente, quando nada mais estava sendo trabalhado. Mas ainda temos esse problema aqui onde, por exemplo, temos esta declaração de saudação impressa. E este ainda está sendo esperado depois disso, só depois que este sono aqui terminar. E saiba idealmente, não gostaríamos que idealmente, esses dois pudessem correr simultaneamente. Então, por exemplo, digamos que tivemos duas chamadas de API aqui que simplesmente não dependiam umas das outras. Então isso aqui atinge API um e isso aqui atinge API para nós de qualquer maneira, mesmo se tivéssemos isso como, assim, ou se tivéssemos o caminho antes, ainda não está funcionando da maneira que queríamos porque estamos basicamente aguardando a resposta de uma chamada de API. E então nós vamos, então nós só estamos iniciando a chamada do segundo, que não é o que nós queremos. Nós queremos que eles basicamente o início quase imediatamente, um após o outro, e então nós queremos que o período de tempo limite se sobreponha para que todo o tempo de espera da rede basicamente não esteja acontecendo sequencialmente, mas está quase acontecendo ao mesmo tempo. De qualquer forma, independentemente de como invertemos esta ordem, não vamos chegar a isso. Então, como podemos fazer algo assim? Bem, podemos usar é algo mais de IO assíncrono, que é chamado de reunir. Então, podemos entrar em IO assíncrono e aqui podemos usar este método e coleta. E aqui podemos agora colocar uma série de corotinas e elas serão basicamente todas programadas e executadas simultaneamente. Então não temos este após o outro, mas eles estão todos programados ao mesmo tempo. E qualquer um, você sabe, o que terminar e que ordem. Basicamente, podemos pular por aí. Ainda há alguma ordem que temos aqui, que é a ordem em que os colocamos. Mas agora somos capazes de executar tudo isso simultaneamente e da maneira que queríamos. Então vamos ver isso em ação. Como faríamos isso? Bem, podemos ter, por exemplo, são a primeira co-rotina aqui, que vai ser a nossa assíncrona. Vamos ter a nossa segunda co-rotina, que é o computador do sono 2 do Eysenck. E então nós vamos ter o nosso terceiro, que vai ser impressão fora de Olá. Agora podemos remover o agendamento desta tarefa. E se fizermos isso agora, notaremos que vamos entrar na antes de dormir, que é aqui. Então vamos entrar no antes de dormir também, que é aqui. Então nós temos nossa impressão baixa porque ambas as rotinas co são, eles não estão bloqueando, mas eles estão essencialmente eles estão esperando uma resposta. E assim eles podem devolver o controle ao nosso ciclo de eventos. Então nós continuamos aqui, nós executamos isso, nós damos esse controle para o loop de eventos. Nós executamos, vamos e aqui executamos, chegamos aqui, recuperamos o controle. Entramos, aqui estão os acabamentos co-rotineiros porque não há espera para sempre. E então podemos voltar para o loop de eventos e o peso do loop de eventos. E então ele vai ver porque este foi agendado primeiro e eles dormem pelo mesmo tempo. Chegamos aqui primeiro. E assim podemos continuar com a execução disto até que, bem, a nossa co-rotina termine aqui. E, em seguida, o controle dá, devolvido ao loop de eventos e, em seguida, vemos o que mais está acontecendo. Então temos este aqui, que depois termina. Então vamos atualizar isso um pouco e também dormir por esse tempo. Veremos que a ordem de agendamento é tipo do que temos aqui, mas a ordem de acabamento pode não ser realmente assim. Então, neste caso, vamos esperar que este seja agendado primeiro. Então recuperaremos o controle. Assim que chegarmos a este ponto, podemos começar a correr. Este aqui. Daria de volta o controle. Se chegarmos a este ponto, podemos executar este. Terminamos toda a co-rotina, e agora voltamos ao nosso ciclo de eventos. E neste ponto, este vai realmente terminar primeiro de antemão porque ele está dormindo por um período mais lento, por um período menos de tempo. Para podermos voltar a esta. Termino esta co-rotina porque não há mais nada a acontecer depois do sono, depois desta impressão digital. E depois temos a única co-rotina que estava esperando, que vai ser esta aqui. Então, se executarmos isso, podemos ver que a ordem em que eles terminam pontos, basicamente podemos continuar com a execução desses pontos. E assim com isso agora nós temos uma natureza muito melhor simultânea porque nós somos capazes de, em vez de ter todas essas declarações p sequenciais, em vez disso, temos todos os tipos de execução simultânea e estamos iniciando-os. E sempre que atingimos este aguarde 0.1 co-rotina, podemos basicamente devolver o controle e outra co-rotina pode continuar em execução. E se nós demos pelo Controle T, pequeno T, então loop e tudo está meio que correndo. Assim que uma coisa terminar, podemos ir até lá e podemos continuar com a execução daquele Coubertin recebendo essa natureza concorrente muito mais agradável que estamos procurando. Então, neste momento você pode estar se perguntando, bem, qual é a diferença entre assíncrono e rosqueamento? Então, geralmente, e se você se lembrar do que falamos no início, nosso assíncrono aqui, isso está sendo executado em um núcleo e também em qualquer thread único e tudo é feito através desses loops de eventos programados onde temos uma maneira de touros e basicamente futuros que representam que uma resposta vai chegar. Mas ainda não está lá. Enquanto que com o threading, estamos criando na verdade vários segmentos diferentes e também há sobrecarga associada a isso. Considerando que aqui estamos apenas em um único segmento e na verdade temos menos sobrecarga. Agora, geralmente, quando você usaria um desses dois? Bem, você usaria ou eu geralmente usaria threading quando estamos construindo trabalhadores como programas como fizemos em nosso módulo de threading, onde tínhamos muitos trabalhadores diferentes realizando objetivos diferentes. Considerando que se você tem apenas tarefas individuais, como temos mais nesses casos, então você pode ir para um síncrono. Obviamente, se você se sentir muito mais confortável com um ou outro, você provavelmente vai tendem a ir para essas coisas e você provavelmente pode ver alcançar simultaneidade semelhante. Embora lembre-se apenas de que com Async você está apenas fazendo um único núcleo, único thread, enquanto que com o threading você está fazendo threads de núcleo único múltiplos. Então há essa diferença lá e também há sobrecarga associada com rosqueamento. Mas obviamente, você sabe, também se resume a conforto um pouco. A outra coisa é que em aplicativos web, muitas vezes você estará usando assíncrono. Portanto, é muito comum ter definições assíncronas e de ponto onde você pode, em seguida, ocultar endpoint e que fica mais quente para o loop de eventos para que você saiba seus diferentes pontos de extremidade e seu servidor em geral é não bloqueando a execução porque está tentando executar coisas em paralelo. Então assíncrono é meio que resumir. Geralmente, da minha perspectiva, usado muito para tarefas, bem como desenvolvimento web. Considerando rosqueamento, eu usaria muito mais para construção de trabalhadores como programas como fizemos de volta em nosso módulo de torneamento maior. 25. Como usar intervalos de tempo de Async: Agora, geralmente quando estamos lidando com comunicação em rede ou algum tipo de Io, pode haver problemas em outros lugares que podem causar algum tipo de interrupção ou basicamente algumas coisas podem levar muito mais tempo. Por exemplo, se um servidor está sobrecarregado ou não está respondendo ou muito lento, se estamos tentando fazer ping nesse servidor e leva uma eternidade para obter uma resposta. Então, mesmo que estejamos usando algum tipo de execução simultânea como temos aqui, pode haver um retardatário que basicamente leva tudo e apenas retarda a coisa toda porque estamos esperando que uma coisa termine. Então, há um bom método que podemos usar para isso. Ter algum tipo de limites sobre quanto tempo queremos esperar por respostas. E nós geralmente sabemos como os endpoints respondem mais rápido, bem como o intervalo de variabilidade que temos. E sabemos que, com muita certeza, somos capazes de obter respostas e menos do que esse período de tempo. E o período de tempo é um bom momento aqui para usar. Nós também podemos usar algo chamado o tempo limite. Então, podemos fazer, por exemplo, é que podemos dizer assíncrono ponto I/O esperar. E isso basicamente significa que vamos esperar por tantos segundos. E se a nossa co-rotina não terminar nesse ponto, então vamos levantar uma exceção de tempo limite para isso. Então vamos dizer que queremos dar cinco segundos. E nós também vamos embrulhar isso em uma tentativa e exceto declaração onde nós vamos especificamente pegar um tempo limite Aram. E aqui vamos imprimir o erro de tempo limite encontrado. Então, neste caso, se executarmos isso, tudo vai ficar bem porque leva dois segundos e sem limite de tempo, são cinco segundos. Mas se mudarmos isto para, digamos, trinta segundos, como se algo estivesse a correr muito devagar ou se houvesse apenas uma janela de tempo limite de 30 segundos e não fosse responsivo. E nós estamos meio que mantendo essa conexão lá e estamos esperando por uma resposta, mas ela nunca vai responder. E a conexão será interrompida após, digamos, 30 segundos. Se colocarmos aqui uma espera por cinco segundos, depois de alcançarmos a marca de 5 segundos, então basicamente vamos acabar com isso. Em vez disso, vamos chegar a um erro, que podemos ver aqui em um segundo. Assim, podemos ver que encontramos um erro de tempo limite. E porque temos esse componente de tempo limite aqui, agora, esteja ciente de que, como estamos encontrando esse caso de exceção, podemos ver que estamos entrando no dorme antes aqui. E nós entramos neste caso de exceção. Então as outras rotinas co que também temos, como podemos ver aqui, que na verdade não têm a oportunidade de terminar porque encontramos essa exceção com o peso para o método. Então, obviamente, isso pode ser uma coisa muito agradável para usar para garantir que as partes de sua execução ou não bloqueadas por um tempo muito longo por causa de razões externas. Mas obviamente você também quer ter cuidado com isso, uma vez que também pode interromper outras coisas que estão em execução se eles estão sendo esperados ao mesmo tempo, como neste caso que temos aqui. 26. Como criar a Asynchronous para loops: Agora outro caso que eu queria rever era assíncrono para loops já que ele às vezes pode ver isso. Mas eu quero rever isso e basicamente olhar para o comportamento para ter certeza de que entendemos exatamente o que é um loop FOR assíncrono e o que ele faz e não faz. Então vamos em frente e mudar nosso sono assíncrono aqui em vez de ser um gerador, que vai apenas produzir valores, e depois ele vai dormir. Então nós vamos dizer para eu no alcance, e nós vamos produzir o resultado I. E então nós vamos dormir por i segundos. E vamos dizer que para eu entre um e n. E vamos dizer que n é igual ao valor máximo entre duas extremidades. E só para fazermos uma coisinha, certo? E então agora o que podemos fazer é usar um loop assíncrono e vamos dizer para k em um sono de pia 5, e então podemos imprimir k. Tudo bem, então vamos em frente e executar isso e vamos também falar sobre o que está acontecendo. Então tivemos nossos cinco anos como entrada só porque, bem, isso ainda está superimprimindo aqui. E então nós estamos basicamente selecionando ela e certificando que são pelo menos dois. E nós estamos entrando em nosso for-loop aqui, e nós estamos começando de um até n. Então vai ser de um até, mas não incluindo cinco. Então, de um a quatro, como vemos aqui. E então nós produzimos essa resposta, e então esperamos esse sono que temos aqui. Agora podemos ver passando por aqui, ou o tempo total de execução é de cerca de dez segundos. Então, se tivermos um mais dois é três, mais três é seis, mais quatro é dez. Então ainda estamos executando isso sequencialmente. Não estamos fazendo isso simultaneamente, caso contrário, nosso tempo de execução será de quatro segundos, uma vez que o sono mais longo que temos aqui, ou cerca de quatro segundos. Então o importante sobre este assíncrono para é que basicamente temos outro estágio onde somos capazes de devolver o controle para o loop de eventos. Então, ao invés de ter um for-loop onde basicamente esse tipo de iteração de tudo acontece, o avante assíncrono nos dá outro estágio em que durante essa iteração, se estamos esperando por uma resposta, podemos novamente devolver o controle para o loop de evento e, em seguida, voltar para a nossa co-rotina assim que estivermos prontos para continuar com o nosso ciclo. Então isso é apenas uma coisa importante de notar que se você vir um piso assíncrono, se você pensar em escrever um assíncrono para, ele não funciona. Ele não é executado simultaneamente e executado sequencialmente, mas basicamente adiciona outro estágio onde podemos dar de volta o controle para o loop de eventos para que outras coisas possam continuar com sua execução. 27. Como usar bibliotecas assíncronas: Então, a próxima coisa que eu queria dar uma olhada é usar outras bibliotecas com processamento assíncrono. Assim, algumas bibliotecas suportam assíncrono e outras não. E eu só quero ir em frente e olhar através deles e basicamente mostrar a vocês uma comparação rápida de, você sabe, como isso seria. Então nós vamos usar, e eu já tenho como um pequeno boilerplate aqui basicamente com alguns URLs que eu peguei. O que vamos fazer é executar um programa muito simples, foi apenas pings cada um desses URLs e então apenas obter a resposta de texto dele. Ele realmente não faz nada com ele, apenas meio que obtê-lo. Então vamos escrever isso de duas maneiras. Um deles vai estar usando a versão síncrona estava indo apenas para usar a biblioteca de solicitações. Então você não tem isso. Você pode ir em frente e escrever solicitações de instalação pip como este. E então nós também vamos usar o HTTP IO, que vai ser HTTP como este pip instalar isso. E um desses, você provavelmente pode adivinhar que vai ser o HTTP vai nos permitir fazê-lo de forma assíncrona enquanto o outro é biblioteca assíncrona. Então vamos começar com o síncrono. Vamos importar pedidos. E o que vamos fazer é correr um pouco por loop. Nós vamos dizer para URL. Em URLs, vamos chamar solicitações ponto obter URL. E então podemos cronometrar nosso processo aqui e podemos dizer o nosso, nossos horários de início time.DeltaMe e nosso tempo final vai ser time.DeltaMe. E então podemos dizer que as cristas tomaram e então temos nosso tempo final menos início. Então nós podemos apenas executar isso e isso vai ser apenas a maneira síncrona típica padrão. E podemos ver que isso vai levar alguns segundos, provavelmente, digamos 3,5 segundos agora. Então vamos em frente e escrever a versão assíncrona dele. E vejamos também os componentes individuais e a calvície. Então nós vamos fazer estão enfrentando a morte e nós vamos dizer obter resposta URL. Vamos passar aqui um URL. E agora vamos usar nossa biblioteca HTTP AIO que acabamos de importar ou que acabamos de instalar. Então vamos importar o HTTP IO assim. E vamos dizer com sessão de cliente http ponto AIO . Como sessão, vamos fazer isso uma largura assíncrona. E falarei sobre isso em um segundo. E vamos fazer assíncrono com sessão, não obter URL como resposta. E, finalmente, vamos retornar um ponto de resposta de peso txt. Então vamos passar por cima de cada uma dessas linhas no segundo. E aqui, é claro, também queremos ter certeza de que obtemos a resposta dos textos. Então podemos dizer que a resposta de texto sincronizado vai ser isso. E aqui podemos apenas acrescentar à nossa lista. E então podemos fazer algo parecido. Mas aqui temos nossas tarefas. E para cada um deles, você deseja assíncrono o, queríamos criar uma nova tarefa, que chamará nossa resposta URL GET. Nós vamos passar. Não é isso que eu quero. Mova-se em tudo. Onde estamos? Aqui? Vamos ligar para ela, passar pela nossa resposta. Nós vamos fornecer nossa URL como entrada aqui. E, em seguida, vamos esperar Async I/O ponto reunir. E nós vamos clicar em todas as nossas tarefas e basicamente descompactar toda esta lista para fornecê-los como argumentos individuais. E então nossa resposta de texto assíncrona será a saída que obtemos a partir disso. E então aqui podemos dizer que solicitações assíncronas levaram isso. Agora vamos em frente e executar isso. E então vamos em frente e voltar a este método aqui. Estamos de volta a esta co-rotina em vez de entender o que exatamente está acontecendo. Então vamos apenas executar isso para que possamos realmente comparar o desempenho. Então, temos nosso processo síncrono acontecendo. Esqueci de inicializar nosso objeto aqui. Então vamos em frente e executar isso mais uma vez. Lá vamos nós. Então, com nosso processo síncrono, levamos um pouco mais de três segundos, e com nosso processo assíncrono, levamos cerca de 1 segundo. Então vamos em frente e dar uma olhada nisso aqui. Então, o que está acontecendo como nós temos vários ritmos diferentes com, então se você programou em Python por um pouco, você provavelmente está familiarizado com a declaração, com, que é basicamente estamos criando algo como um contexto ou raciocínio ou Gerenciador de Contexto, que basicamente lida com a criação, bem como o desmantelamento de tudo o que temos e não temos que nos preocupar em fechar algo. Nós fomos capazes de usá-lo dentro deste contexto deste com declaração aqui. Agora o assíncrono com que vemos aqui duas vezes. Cada uma dessas vezes estamos basicamente dando a oportunidade para o loop de eventos. Segundo, estamos basicamente dando o controle de volta ao loop de eventos e estamos dando a oportunidade de iniciar ou continuar com outras tarefas. Então, basicamente aqui temos três instâncias, uma com o peso e as outras duas com nossos gerenciadores de contextos assíncronos aqui, onde estamos dando controle de volta ao loop de eventos para que ele possa potencialmente continuar com outra coisa. Então, há um monte de devolver o controle para o loop de eventos que está acontecendo aqui. Isso realmente faz com que seja realmente agradável e como assíncrono, e especialmente com essas partes diferentes. Então, um deles realmente estaria recebendo uma sessão do nosso pool de sessões. Em seguida, o próximo seria realmente executar as solicitações, que envolveria um monte de espera da rede. E então o outro componente seria realmente obter a resposta HTML completa, porque podemos nem sempre ter isso. E então temos que reunir todos esses dados e basicamente analisá-los em uma variável. E também há algum tempo de espera envolvido aqui. Então, para cada um desses componentes onde nós realmente pode estar tendo algum tipo de componente de espera. Nós basicamente devolvemos o controle para o loop de eventos até que estejamos prontos para continuar com isso. Então, há um monte de assíncrono ou há um monte de dar de volta o controle para o loop de eventos. Essas chamadas diferentes que estamos fazendo aqui, basicamente estamos fazendo isso três vezes. Considerando que para os nossos pedidos, obviamente, a biblioteca de pedidos em si. Onde estamos? Aqui vamos nós. Então isso em si é apenas uma espécie de chamada de bloqueio. E não há, não há nenhuma obtenção assíncrona de uma sessão de um pool. Também não estamos usando sessões neste caso. Não estamos de forma assíncrona, você sabe, recebendo o pedido como seria neste caso. E também não estamos de forma assíncrona de obter esses dados HTML e tê-los reunidos em segundo plano e, em seguida, continuar e estamos prontos para isso. Agora, é claro, podemos otimizar isso um pouco e podemos colocar esse self em como uma definição assíncrona, obter URLs com solicitações, e vamos colocar o URL aqui. E então aqui podemos fazer aqui, podemos apenas devolver isso. Mas como você provavelmente também notará em um segundo, se tivermos nossas tarefas aqui e agendar essas tarefas. Então vamos para uma pia, io ponto criar tarefas e vamos testar fora de canetas. E se quisermos criar isso como uma tarefa, passando o parâmetro URL, ainda não há chamada de espera em nenhum lugar. Então, mesmo se tentarmos usar esse método assíncrono de assíncrono, eu sei que Don se reúne, e nós apenas tentamos executar todas essas tarefas de forma assíncrona. E em algum lugar aqui nós deveríamos ter nossa resposta de texto pia, eu acho que foi chamado. Então, mesmo que tentemos usar essa abordagem, não vamos realmente obter nenhum benefício de desempenho porque não há chamada de espera em lugar algum. Não há ponto em que devolvemos o controle ao ciclo de eventos. Então, mesmo se tentarmos envolver isso em como uma função assíncrona, como podemos ver aqui. Tudo isso é um processo síncrono e está completamente bloqueado. Considerando que em nosso processo assíncrono, basicamente temos essas diferentes oportunidades e obter a sessão do pool, o desempenho real da solicitação, bem como a análise da resposta de textos para obter um texto resposta para fora. Cada um desses três componentes basicamente nos permite dar controle de volta ao loop de eventos que outras coisas possam acontecer simultaneamente ou enquanto essa coisa está esperando em vez disso. Enquanto que no nosso caso síncrono, não temos oportunidade de fazer isso e estamos basicamente bloqueados até que este pedido o envie, obtém a resposta, analisa a resposta dos textos. Então tudo isso é um processo de bloqueio. Então, como podemos ver, há alguns grandes benefícios que podemos realmente obter o uso de solicitações assíncronas obviamente. Mas temos que ter cuidado para que também estejamos usando a biblioteca assíncrona apropriada. Então, neste caso, ele vai ser um 0 HTTP para entrada e saída de arquivo. Há também algo chamado arquivo AI, que você pode usar onde você pode fazer leitura e escrita de arquivos, bem como apenas operações gerais de arquivo tipo de assíncrono como este. Há também outras coisas como conexões de banco de dados. Há muitas bibliotecas assíncronas que você pode reutilizar para isso. Mas você tem que ter certeza de que se você tentar fazer isso assíncrono, você tem que usar as bibliotecas apropriadas também que suportam essa maneira assíncrona. Caso contrário, você só vai ter componentes de bloqueio porque é um processo síncrono e não há controle sendo devolvido ao loop de eventos. 28. A declaração de espera em Async: Tudo bem, então nós vimos algumas coisas bem legais agora com processos assíncronos. Mas vamos em frente e olhar para mais uma coisa legal, que vai estar esperando até que algumas coordenadas sejam concluídas ou algumas tarefas concluídas e, em seguida, lidar com elas e tipo de ir sobre isso iterativamente. Porque atualmente o que vimos com a reunião é que estamos basicamente aguardando tudo para ser concluído. O que significa que se tivermos um monte de coisas que levam pouco tempo e uma delas é um retardado. Isto também pode, obviamente, abrandar o nosso programa. Então eu vou importar novamente E/S assíncrona. Vou ter o meu nome se for igual a principal. E aqui eu estou indo para o ponto I/O assíncrono, executar nossa co-rotina principal, e vamos em frente e descobrir isso. Eu escreverei. E também vou usar o sono de novo. Então nós vamos entrar em definição assíncrona e vamos chamar isso de nosso sono assíncrono novamente. E aqui vamos ter um perímetro. Só por quanto tempo vamos dormir. Ou se quisermos, podemos ver isso um pouco mais explícito sobre eles e chamá-lo de algo como uma duração. E então vamos dizer que vamos aguardar o sono de ponto de E/S assíncrono durante a duração. E então nós vamos apenas retornar a duração. Apenas levou, também tem algo devolvido de lá. Tudo bem, então na nossa Corotina principal aqui, basicamente o que eu quero fazer é agendar 10 tarefas. E quando um deles terminar, quero ser capaz de lidar com eles. Então o que eu vou fazer é eu vou ter uma variável aqui chamada pendente. E você verá por que em um segundo, que eu vou inicializar para ser apenas um conjunto vazio. Então eu vou iterar para eu no intervalo de um a 11. E para cada um desses, vou adicionar um elemento. E vamos dizer assíncrono I/O dot criar tarefa. Então vamos criar nosso sono assíncrono com a duração específica. Então agora e já vimos a tarefa de criar antes. Estamos apenas criando um monte de tarefas que estamos adicionando a este conjunto aqui que chamamos pendentes. Está bem? Então agora podemos usar algo chamado Assíncrono, IO dot wait. E aqui podemos fornecer um intervalo de tarefas. Assim, por exemplo, um conjunto ou uma lista de tarefas. E, e podemos ter um comportamento diferente para isso, que é o que veremos em um segundo. Então vamos apenas mantê-lo com o comportamento padrão por enquanto. Então vamos ter nosso primeiro intervalo de tarefas, que será apenas o pendente que temos aqui. E o retorno que realmente obtemos dele. As variáveis são chamadas feito, bem como pendente. Então é por isso que temos esse nome de variável aqui. Porque as respostas que recebemos são divididas em duas coisas. Então essas são as tarefas que foram concluídas e as amarelas, as tarefas que ainda estão pendentes. Então vamos deixar isto assim por enquanto. E então nós vamos apenas imprimir são tarefas feitas. E também imprimimos nossas tarefas pendentes. E deixando isso como está por agora e faremos mais algumas mudanças em um segundo. Vamos apenas ir em frente e executar isso primeiro. E sim, vá em frente e aperte Enter. Então deve levar cerca de 10 segundos. Eu realmente não tenho nenhuma impressão extra aqui, infelizmente agora exceto por estão feitas e pendentes no final aqui. Mas lá vamos nós. Então nós temos o nosso primeiro conjunto de resultados, que vai ser este aqui. E podemos ver que temos um conjunto que tipo de tem a tarefa, bem como o resultado que realmente veio com ele. E então nós finalmente também temos este conjunto vazio aqui, que é basicamente as tarefas pendentes restantes. Então temos algo legal, mas essencialmente o que temos agora é a mesma coisa que já temos com a reunião em essência porque ainda estamos esperando que tudo termine. Então, há maneiras diferentes de fazermos isso. Uma das coisas que podemos fazer é adicionar algo como um tempo limite. Agora desta vez em é diferente do que tínhamos para o peso para, neste caso, estamos basicamente verificando ou vamos basicamente obter nosso resultado aqui para Don e Pending assim que atingirmos esse limite de tempo. Mas isso não significa que nossas tarefas agendadas serão canceladas. Significa que teremos nossa resposta nesse momento. Então o que podemos fazer é dizer, enquanto ainda há tarefas pendentes. Então, enquanto o comprimento do nosso conjunto pendente é maior que 0, vamos avançar e imprimir isso. Então, se executarmos isso, agora, devemos vê-lo imprimir a cada dois segundos, que é o que temos aqui. Obviamente, há muito spam em nossa saída, como podemos ver, porque é muito detalhado. Cada um desses elementos, há um monte de detalhes para ele, mas podemos ver o conjunto que temos para anexar resultados é basicamente tipo de apenas continuamente diminuindo de tamanho. E assim a cada dois segundos nós meio que voltamos e vemos quais resultados já terminaram. Então, o que está dentro está feito. E então nós apenas continuamos com as tarefas pendentes atuais. Agora, obviamente, se você quiser obter resultados, nós provavelmente também queremos fazer isso. E assim nós podemos realmente iterar sobre são feitas tarefas. E podemos dizer para tarefas feitas, portal dizer para Don tarefa e feito se você quiser obter o resultado, podemos apenas esperar, esperar esse elemento ou podemos esperar essa tarefa. E a partir daí podemos obter o resultado que temos aqui. Então vamos em frente e executar isso mais uma vez. Então vamos ver basicamente a ordem em que esperaríamos que essas tarefas terminassem. Então podemos ver aqui que a cada dois segundos, essencialmente, estamos parando isso ou estamos atingindo um tempo limite para nosso Coubertin aqui e estamos recebendo as respostas. Mas essas tarefas ainda foram agendadas e não são tecnicamente e progresso como podemos ver, porque é a cada dois segundos que meio que recebemos as respostas. E então podemos passar por cima deles. E se usarmos esta espera, podemos obter o resultado real como este. Mas obviamente isso é, isso é muito bom porque agora nós não temos que esperar que tudo termine, mas nós podemos tipo de processos em pedaços como ele termina. E, claro, algo que também podemos fazer é adicionar mais coisas à lista pendente ou ao conjunto pendente neste caso. Então o que nós poderíamos fazer, por exemplo, é que nós poderíamos, você sabe, no fundo aqui apenas, nós temos mais tarefas para adicionar. Eu só vou fazer um muito simples apenas adicionar uma tarefa que dorme uma vez. E vamos basicamente dizer, vamos fazer isso uma vez. Adicionar tarefa é igual a false. E então vamos dizer, se essa tarefa era verdadeira, se adicionar tarefa, então queremos adicionar a tarefa e vamos apenas definir esta variável como false. Então isso é apenas infinitamente e basicamente ficar preso neste loop. Mas o ponto que eu estou tentando fazer com isso é que nós podemos apenas continuar a adicionar mais tarefas para, neste caso, estão pendentes definir. E isso nos dá muito mais flexibilidade porque, à medida que as coisas entram, podemos continuar a criar e agendar essas tarefas. E podemos obter essas respostas sempre que estiverem prontas usando esse peso de ponto de E/S assíncrono. Neste caso, estamos usando um tempo limite específico, mas na verdade também há um método diferente disponível para nós. E esse parâmetro é chamado de retorno quando. E aqui podemos ter diferentes opções. O padrão, eu acho, está tudo concluído, escrito em todas as maiúsculas. Então, se não definirmos um tempo limite, então só teremos nossa resposta quando todas as tarefas tiverem sido concluídas. E isso é o que vimos no início quando não fornecemos esse parâmetro, que basicamente estamos esperando que tudo termine. Então vamos ver de um a 10 impressos. E então quando o adicionarmos, vamos ver outro no final aqui. E podemos ver que basicamente estamos esperando que tudo termine. Esta não é uma ordem porque os conjuntos não são ordenados. Então estamos apenas recebendo todas as tarefas concluídas como temos aqui. Mas também podemos mudar isso, mas não estamos se realmente não quisermos usar um tempo limite também porque talvez suas tarefas estejam realmente terminando extremamente rápido e não temos certeza do que usar lá, ou meio que quero fazer isso como as tarefas terminam. Também podemos usar a declaração de retorno um para ser concluída pela primeira vez. Então isso significa que sempre que algo se completa, então nós basicamente meio que sair desta co-rotina aqui e podemos continuar com o resto. Então, neste caso, vamos ver esses números impressos um por um em ordem. Como podemos ver aqui. Isso é porque cada segundo de nossas corotinas, é realmente uma de nossas tarefas, ele está realmente completando. Então podemos ver que isso também é realmente muito, coisa muito legal de se fazer. Porque em comparação com todas as outras coisas, você sabe, nós podemos ter problemas lá atrás onde basicamente, você sabe, se uma coisa leva muito, muito mais tempo para correr do que tudo o resto, então ainda vamos estar gastando muito tempo Esperando. E então essa corotina de pesos que temos disponível para nós realmente nos permite muito mais flexibilidade nesse sentido para realmente obter duas coisas, ou quando elas estão prontas ou também dentro intervalo de tempo específico para que possamos continuar processamento de coisas que são feitas. E também podemos adicionar mais tarefas para que eles também começaram a trabalhar para realmente obter um programa muito mais dinâmico e ainda mais simultâneo. 29. Combinando a sincronização e multiprocessamento: Tudo bem, agora eu quero dar uma olhada em como podemos combinar multiprocessamento e programação assíncrona. Porque anteriormente falamos sobre isso só podemos ter um loop de evento por thread. Mas algo que temos que lembrar em Python é que também temos essa coisa chamada bloqueio de intérprete global, que basicamente limita a simultaneidade real que podemos obter. Mas felizmente, quando fazemos multiprocessamento, temos uma Gill por processo. Assim, podemos fazer muito uso do hardware completo disponível para nós, bem como algumas das limitações da simultaneidade do Python usando multiprocessamento e combinação com assíncrono. Então vamos em frente e importar E/S assíncrona. E também vamos em frente e importar multiprocessamento. E nós vamos ter são se o nome é igual a chamada principal. Mas, por enquanto, vamos passar isso. E agora o que eu vou fazer é definir uma classe chamada multi processamento assíncrono. E isso vai herdar do multiprocessamento, não processe. E então o que esta turma vai fazer é criar um processo para nós. E neste processo, vamos então iniciar nosso loop de eventos assíncronos. Então vamos em frente e chamar a inicialização e apenas inicializar a classe pai. E também vamos fornecer como parâmetros algumas durações porque o que vamos fazer é apenas emular algum tipo de temporizador de E/S de rede de longa duração ou apenas outro tempo de E/S para apenas usar a co-rotina de sono novamente. Então vamos ter nosso assíncrono definido. E vamos chamar isso de “sono assíncrono”. E aqui podemos passar a duração. E tudo o que vamos fazer é esperar o nosso sono de ponto de E/S assíncrono por esta duração. E isso podemos realmente fazer um método estático já que não estamos usando nenhum dos nossos atributos de classe aqui. Então também precisamos do nosso método de execução. Então isto vamos definir apenas o caminho normal. E em nosso método de execução, eles estão aqui nós queremos começar realmente a consumir nosso loop de eventos. Então, vamos em frente para a execução de ponto de E/S assíncrona. E agora precisamos fornecer o principal ponto de entrada para o nosso ciclo de eventos, o que queríamos fazer. Então também precisávamos encontrar essa co-rotina dentro da nossa turma. Então vamos entrar em definição assíncrona. E então nós só vamos, Ei, eu tenho aqui, vamos chamar isso de sono consecutivo. E o que vamos fazer aqui é ter uma lista de tarefas que vamos primeiro agendar e depois vamos esperar por elas. Então vamos em frente e bem, podemos ter nosso pendente, que será nosso set novamente. E então vamos dizer por duração, em durações para o nosso pendente. Vamos adicionar e, em seguida, vamos criar uma tarefa. Então, vamos criar uma tarefa usando o auto.idade assíncrono, dormir por esta duração. Então, basicamente, o que fizemos também na última lição, temos nosso conjunto pendente. Então vamos agendar um monte de tarefas com base nas durações de entrada aqui. E nós vamos ter que todos manter o controle de tudo lá dentro pendente set. E então vamos dizer, enquanto o comprimento da patente é maior que 0. E então vamos dizer feito e ofensivo igual ao peso de ponto IO assíncrono. E vamos esperar por nossas tarefas agendadas. E vamos usar um tempo limite de apenas 1 segundo aqui. E vamos dizer quatro, feito tarefa e feito. Vamos imprimir a resposta que temos e a tarefa que atualmente não é nada. Então vamos em frente aqui e apenas retornar a duração só para que nós estamos devolvendo algo. Tudo bem, e então nós vamos chamar isso em nosso método de entrada para a classe multiprocessamento. Então aqui vamos executar o nosso código, auto-dot deslizamentos consecutivos. Certo, então vamos rever isso mais uma vez em termos do que estamos realmente fazendo aqui. Estamos herdando da classe de processo de ponto multiprocessamento. E isso significa que quando iniciamos essa classe, estamos iniciando essencialmente uma criança que herda desse processo. Então, podemos criar um novo processo para isso que pode ser executado em um núcleo separado nós separado CPU. Também vamos fornecer-lhe um conjunto de durações. Novamente, isso é apenas para ter algo aqui para que alguma tarefa se conecte a ser realizada para nós. Agora nosso ponto de entrada, e você vai se lembrar disso de roscar. Nós não entramos em muitos detalhes para isso, para multiprocessamento, mas você vai se lembrar disso de threading. É sempre que chamamos os pontos de início, É aí que vamos executar este método de execução aqui. E em nosso método de execução, tudo o que estamos fazendo é fornecer o ponto de entrada para nosso processo assíncrono. Então vamos chamar Async IO dot run. E aqui nós vamos apenas ter a co-rotina principal, que vai ser este sono consecutivo, que nós definimos aqui. E agora isso você provavelmente reconhecerá da lição anterior em que estamos apenas adicionando apenas agendando um conjunto de tarefas. E cada uma dessas tarefas só vai dormir por uma certa duração. E, enquanto ainda temos tarefas pendentes, vamos usar esse método de I/O assíncrono não esperar. Usando nossas tarefas pendentes aqui com um tempo limite de 1 segundo e cada segundo que vamos fazer loop são tarefas feitas e vamos imprimir os resultados usando esta chamada de espera aqui. Então agora a coisa legal com isso é que podemos criar vários processos. E eles podem então, nós podemos dividir o trabalho assim. E podemos realmente ter vários loops de eventos em execução. Um vai estar em cada processo. Então vamos criar as durações iniciais, que podemos apenas inicializar para serem vazias. E então vamos dizer para eu na faixa de 1 a 11, assim como fizemos por duas durações, vamos acrescentar I. E agora também podemos criar dois processos se quisermos. Então vamos apenas ter nossa lista aqui de processos. E nós vamos dizer para eu na faixa 2, e eu não vou fazer muito aqui. Vou acrescentar ao nosso processo e versão inicializada do nosso ás multiprocessamento e classe aqui. E vamos inicializá-lo com algumas durações. E essas serão durações. E então nós vamos de i para, então você tem que fazer I vezes 5, até I mais 1 vezes 5. E assim por diante. Dessa forma, vamos basicamente apenas um incremento de cinco. Então, quando eu tiver 0, vamos de 0 a 5. Então, serão os primeiros cinco elementos. E quando eu for um e vamos de cinco para 10. Então, basicamente, tecnologia pegando os cinco segundos elementos de lá. E agora temos nossos dois processos, mas ainda precisamos iniciá-los. Então vamos dizer para P e processos, vamos apenas chamar p ponto start no final para p e processos, vamos chamar P dot join. Então estamos esperando que eles terminem. Tudo bem, então vamos em frente e executar isso. E parece que eu tenho um erro de sintaxe aqui em cima. Então deixe-me ir em frente e dar uma olhada no que está acontecendo aqui. E vamos seguir em frente e percorrer nossos registros. Então nosso Coubertin nunca foi um peso. Então vamos tentar isso mais uma vez. Lá vamos nós. Então agora estamos basicamente rodando em dois processos separados. E sim, nós somos capazes de fazer isso bem. Um deles está agendando um conjunto de tarefas aqui eles querem um agendamento do outro conjunto de tarefas. Obviamente, isso não é super ideal porque bem, para começar, estamos apenas dormindo por dez segundos e temos um monte de a tarefa mais curta em um processo e um monte de o teste mais longo definir outro. Então um processo vai realmente terminar. Então também podemos imprimir aqui. Processo concluído em processos vão terminar antes do outro, o que significa que há algum tempo em que uma de nossas duas CPUs neste caso que estamos usando ou sempre que dois núcleos que estamos usando está ocioso enquanto o outro é Ainda está correndo. Então, obviamente, podemos distribuir melhor essa carga de trabalho para ter um efeito melhor a partir dela. Mas ainda está, está funcionando bem. Então agora somos capazes de combinar um multiprocessamento, bem como assíncrono juntos e fomos capazes de contornar algumas das limitações que teríamos com um único thread e apenas ser capaz de executar um único loop de evento. E basicamente aproveitando o máximo de um hardware se tivermos mais de um núcleo, sendo capaz de fazer uso de multiprocessamento. E, por meio disso, ser capaz de ter um loop de evento individual em execução em cada processo individual, o que espero também pode nos ajudar a acelerar ainda mais as coisas. Porque nós podemos chegar a essas limitações onde nós realmente ainda vamos gastar muito tempo esperando só porque, você sabe, quaisquer que sejam as razões que pode haver, você sabe, as coisas são apenas lentas e nós ainda podemos, mesmo que temos rotinas co, se temos milhares de rotinas co são de repente com tarefas agendadas, nós ainda só podemos desligar entre um deles de cada vez. Então, se tivermos mais de um loop de eventos, estamos em mais de um processo, podemos realmente passar por mais trabalho mais rápido. E quando as tarefas são feitas, podemos chegar a eles mais rápido ou quando eles estão terminados, Eles estão aguardando processo. Podemos voltar a eles mais rápido para que possam continuar seu trabalho mais rápido ou passar coisas a jusante e ficar realmente complicadas. Também como fizemos em nosso exemplo de encadeamento. Mas realmente levando isso para o próximo nível, porque agora estamos combinando esse comportamento assíncrono no qual podemos obter essa simultaneidade, bem como o multiprocessamento, que nos dá simultaneidade extra com computação extra. E assim, somos capazes de lidar com os tempos limite de rede com o processo assíncrono ou apenas com E/S geral, nem mesmo com o tempo limite para ser apenas tempos de espera de E/S gerais. E podemos aproveitar ao máximo o nosso hardware usando o multiprocessamento que possamos usar todos os recursos disponíveis para nós e fazer o melhor uso disso. Agora, uma última coisa que eu quero mencionar, que é algo que não encontramos aqui e pode nem ser algo com que você tenha que lidar, mas apenas esteja ciente às vezes que as tarefas também podem ter tempo limite. Então, se você está agendando muitas coisas e você tem algum parâmetro de tempo limite lá. Pode ser que suas tarefas realmente cronometrar antes mesmo que você possa chegar até eles. Então, apenas tenha cuidado com isso se você começar a correr em alguns problemas extremamente estranhos porque você construiu este programa extremamente complexo que está apenas fazendo um monte de trabalho, então isso pode ser algo que você quer olhar para fora é, você sabe, I meu agendamento muitas tarefas ao mesmo tempo e ou alguns deles realmente cronometrar antes que eu possa mesmo começar a lidar com eles. Nesse caso, você pode querer reduzir seus tamanhos de lote que você possa passar por eles de uma maneira melhor. Então apenas uma última dica que eles são se você vai realmente fundo com isso e tentar construir algo muito grande e complexo que vai cuidar de um monte de coisas. Apenas esteja ciente dos tamanhos de lote. Porque, você sabe, isso pode ser algo pode nem ser, mas pode ser algo que você pode encontrar. E posso causar muita dor de cabeça se não tiver certeza do que está procurando. Mas sim, então eu espero que você tenha gostado disso e eu espero que você tenha aprendido muito e eu espero que você possa construir alguns programas simultâneos e paralelos realmente legais agora.