Programação Assíncrona com Python

Cansado de programar?

Cansado(a) de quebrar a cabeça para aprender a programar Python de verdade?

Conheça a melhor e mais completa formação de Python e Django e sinta-se um programador verdadeiramente competente. Além de Python e Django, você também vai aprender Banco de Dados, SQL, HTML, CSS, Javascript, Bootstrap e muito mais!

Quero aprender Python e Django de Verdade! Quero aprender!
Suporte

Tire suas dúvidas diretamente com o professor

Suporte

Projetos práticos voltados para o mercado de trabalho

Suporte

Formação moderna com foco na prática profissional

Salve salve Pythonista :wave:

Hoje iremos mergulhar no universo da Programação Assíncrona utilizando nossa linguagem do coração, o Python.

Para quem procura um guia completo que vai desde a introdução básica, explicando o que é programação assíncrona, até um mergulho no funcionamento do processador e do sistema operacional, este é o lugar certo.

Aqui, você aprenderá a dar um boost no seu código, fazendo com que ele execute em paralelo e ganhe desempenho e eficiência.

Mostraremos também as bibliotecas built-in do Python especialmente feitas para esse tipo de tarefa.

Então prepare-se para muitos exemplos práticos, códigos e até um mini-projeto utilizando programação assíncrona!

Vá Direto ao Assunto…

Introdução à Programação Assíncrona

Vamos começar pelo princípio: o que é programação assíncrona?

Em duas palavra, programação assíncrona é sobre não esperar.

Normalmente, quando o nosso código necessita de algum recurso, seja um arquivo no disco, um dado vindo da rede, ou simplesmente um cálculo longo, ele simplesmente para e espera esse recurso ficar disponível.

Nesse meio tempo, o processador fica lá, sem fazer nada.

Agora imagine se em vez de esperar, ele pudesse executar outra parte do código que não dependesse desse recurso?

É exatamente isso que a programação assíncrona faz.

Em vez de bloquear a execução esperando algum recurso, o código é capaz de “pular” essa parte e continuar a execução em outro lugar.

Quando o recurso finalmente fica disponível, o código pode retomar de onde parou.

Agora vamos ao “Hello World” da programação assíncrona com Python:

1
2
3
4
5
6
7
8
9
import asyncio

async def main():
    print('Olá ...')
    await asyncio.sleep(5)
    print('... Mundo')

# Python 3.7+
asyncio.run(main())

E como aqui na Python Academy nós gostamos de te entregar tudo mastigado, vamos às explicações:

  • async def main(): Esta é a definição de uma função assíncrona. A palavra-chave async indica que a função é assíncrona e pode usar await para aguardar outras operações assíncronas.
  • await asyncio.sleep(5): Esta linha faz a função main aguardar assincronamente por 5 segundos. Durante este tempo, outras partes do programa podem continuar executando. asyncio.sleep(5) é uma função assíncrona que simula uma operação de bloqueio (como uma operação de I/O), mas sem realmente bloquear.
  • asyncio.run(main()): Esta é a maneira de iniciar e gerenciar a execução da função assíncrona main(). asyncio.run é uma função que executa a coroutine main() e não retorna até que a main() esteja completa.

Como o Processador e o Sistema Operacional Tratam a Programação Assíncrona

A verdade é que, internamente, o processador e o sistema operacional não estão fazendo nada muito diferente quando se trata de programação assíncrona.

O que muda é a forma como o programa é estruturado.

O programa consegue organizar-se de forma que o processador sempre tem algum código para executar, nunca ficando parado.

A biblioteca asyncio que vimos no exemplo anterior é um exemplo de um tipo de sistema chamado event loop.

A função asyncio.run() que usamos para executar nosso código assíncrono na verdade está iniciando um event loop, e o await asyncio.sleep(5) está suspendendo a execução da função e retornando o controle à este event loop.

Programando Assincronamente em Python

Trabalhar com código assíncrono em Python é bastante direto, graças à introdução das palavras-chave async e await a partir do Python 3.5.

Basicamente, uma função é declarada como assíncrona usando a palavra-chave async def no lugar de def:

1
2
async def minha_funcao():
    print("Olá, Mundo Assíncrono!")

Agora, essa função é uma coroutine, e pode ser pausada e retomada.

A pausa é feita através da palavra-chave await, seguida de uma expressão que retorna uma coroutine:

1
2
3
4
async def minha_funcao():
    print("Iniciando...")
    await asyncio.sleep(1)
    print("...terminou!")

Nesse exemplo, a função asyncio.sleep(1) é uma coroutine que simula um delay de 1 segundo.

Mas em vez de bloquear a execução, ela apenas indica ao event loop que a execução atual deve ser suspensa, e que deve ser retomada depois do tempo especificado.

Quer aprender isso e muito mais e se tornar um Expert em Python e Django? Então clique no botão abaixo e venha fazer parte da Jornada Python agora mesmo!

Jornada Python Jornada Python

Programação Assíncrona com aiohttp

Python já vem com várias bibliotecas prontas para auxiliar na programação assíncrona, sendo a mais conhecida delas a asyncio, que já mencionamos antes.

Além dela, podemos fazer a instalação da aiohttp para fazer requisições HTTP assíncronas com pip install aiohttp.

Vamos ver um exemplo de como utilizá-la para fazer requisições assíncronas ao site Oficial do Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
import aiohttp
import asyncio

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    async with aiohttp.ClientSession() as session:
        html = await fetch(session, 'http://python.org')
        print(html)

asyncio.run(main())

Nesse exemplo, a função fetch() está fazendo uma requisição HTTP usando a biblioteca aiohttp.

Ela é uma função assíncrona, e pode ser pausada e retomada.

Note que estamos usando a palavra await tanto para esperar a resposta HTTP como para ler o texto da resposta.

Ao final da execução, você verá o código HTML da página na saída do programa!

Exemplos de Programação Assíncrona em Python

Vamos mostrar agora alguns exemplos de utilização da programação assíncrona em Python.

Exemplo 1: Função Assíncrona simples

1
2
3
4
5
6
7
8
9
import asyncio

async def contar_ate_dez():
    for i in range(10):
        print(i)
        await asyncio.sleep(1)
    print("Contei até dez!")

asyncio.run(contar_ate_dez())

A função contar_ate_dez() é uma função assíncrona que imprime os números de 0 a 9, com um intervalo de 1 segundo entre eles.

Ela utiliza o comando await asyncio.sleep(1) para esperar assincronamente por 1 segundo.

Colocando-o em execução, você verá a seguinte saída:

1
2
3
4
5
6
7
8
9
10
11
0
1
2
3
4
5
6
7
8
9
Contei até dez!

Está curtindo esse conteúdo? :thumbsup:

Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?

Sua assinatura não pôde ser validada.
Você fez sua assinatura com sucesso.

Assine a PyDicas e receba 30 dias do melhor conteúdo Python direto na sua Caixa de Entrada: direto e sem enrolação!

Exemplo 2: Executando múltiplas coroutines

Vamos ver nesse exemplo como executar múltiplas funções assíncronas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import asyncio

async def contar_ate_dez(nome):
    for i in range(10):
        print(f'{nome}: {i}')

        # Simula uma operação demorada...
        await asyncio.sleep(1) 

async def main():
    await asyncio.gather(
        contar_ate_dez('Tarefa 1'),
        contar_ate_dez('Tarefa 2')
    )

asyncio.run(main())

Esse exemplo mostra como executar várias coroutines em paralelo.

A função asyncio.gather() é usada para combinar várias coroutines em uma única tarefa.

Elas serão executadas assincronamente, e a função await asyncio.gather() só vai completar quando todas elas tiverem completado.

Mini Projeto com Programação Assíncrona

Para terminar, vamos fazer um mini-projeto utilizando programação assíncrona.

Vamos fazer um Crawler simples que vai baixar várias páginas web em paralelo.

Ele utilizará o aiohttp, portanto não esqueça de fazer sua instalação com pip install aiohttp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import asyncio
import aiohttp

lista_urls = [
    'http://python.org',
    'http://google.com',
    'http://facebook.com',
    # Adicione quantas URLs quiser aqui...
]

async def fetch_page(session, url):
    async with session.get(url) as response:
        return await response.text()

async def fetch_all_pages():
    async with aiohttp.ClientSession() as session:
        tasks = []
        for url in lista_urls:
            tasks.append(fetch_page(session, url))
        pages = await asyncio.gather(*tasks)
        return pages

async def main():
    pages = await fetch_all_pages()
    for i, page in enumerate(pages):
        print(f'PÁGINA {i}:\n {page[:150]}...\n\n{"*" * 30}')

asyncio.run(main())

Nesse código, fetch_page() é uma coroutine que baixa uma página web usando a biblioteca aiohttp.

A função fetch_all_pages() usa a função asyncio.gather() para baixar todas as páginas em paralelo, e retorna uma lista com o conteúdo de todas elas.

Ao final da sua execução, será mostrado os 150 primeiros caracteres de cada página:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PÁGINA 0:
 <!doctype html>
<!--[if lt IE 7]>   <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]-->
<!--[if IE 7]>      <html class="no-js ie7 lt-ie8 lt-...

******************************
PÁGINA 1:
 <!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="pt-BR"><head><meta content="text/html; charset=UTF-8" http-equiv="Content...

******************************
PÁGINA 2:
 <!DOCTYPE html>
<html lang="pt" id="facebook" class="no_js">
<head><meta charset="utf-8" /><meta name="referrer" content="default" id="meta_referrer" ...

******************************

Em posse desses dados, você pode fazer qualquer tipo de processamento!

Você pode acessar outras páginas, como páginas de notícias, e-commerces para verificação de preços entre outras várias possibilidades!

Conclusão

Nesse artigo, vimos como melhorar a eficiência de nossos programas em Python usando a programação assíncrona.

Aprendemos o que é essa técnica, como ela funciona a nível de processador e sistema operacional, e como utilizar as palavras-chave async e await para trabalhar com coroutines em Python.

Também vimos como as bibliotecas Python como asyncio e aiohttp podem facilitar muito a nossa vida na hora de programar assincronamente.

Com a programação assíncrona, nosso código nunca mais precisará ficar parado esperando um recurso ficar disponível.

Agora, ele poderá “pular” essa espera e continuar executando outra coisa.

Isso pode dar um boost significativo no desempenho de nossos programas.

Espero que esse tutorial tenha sido útil, e até a próxima, Pythonista!

#newsletter Olá :wave: Curtiu o artigo? Então faça parte da nossa Newsletter! Privacidade Não se preocupe, respeitamos sua privacidade. Você pode se descadastrar a qualquer momento.