Pular para o conteúdo principal

Asyncio: uma introdução

Uma breve introdução à I/O assíncrona com o pacote asyncio.
Atualizado 17 de set. de 2026  · 12 min lido

Explorar com IA

ChatGPTClaudePerplexity

O módulo asyncio foi adicionado ao Python na versão 3.4 como um pacote provisório. Isso significa que é possível que o asyncio sofra mudanças incompatíveis com versões anteriores ou até seja removido em um futuro lançamento do Python.

De acordo com a documentação, o asyncio “fornece infraestrutura para escrever código concorrente de thread única usando corrotinas, multiplexar acesso de I/O por sockets e outros recursos, executar clientes e servidores de rede e outros primitivos relacionados”. Este capítulo não pretende cobrir tudo o que você pode fazer com o asyncio, mas você vai aprender como usar o módulo e por que ele é útil.

Se você precisa de algo como o asyncio em uma versão mais antiga do Python, vale a pena dar uma olhada no Twisted ou no gevent.

Definições

O módulo asyncio fornece um framework que gira em torno do event loop (laço de eventos). Um event loop basicamente fica aguardando algo acontecer e então reage a esse evento. Ele é responsável por lidar com I/O e eventos do sistema, entre outras coisas.

O asyncio na verdade tem várias implementações de loop disponíveis. Por padrão, o módulo escolhe a que provavelmente é mais eficiente para o sistema operacional em que está rodando; ainda assim, você pode escolher explicitamente o event loop, se quiser. Um event loop essencialmente diz “quando o evento A acontecer, reaja com a função B”.

Pense em um servidor enquanto espera alguém solicitar um recurso, como uma página web. Se o site não é muito popular, o servidor ficará ocioso por um bom tempo. Mas quando chega um acesso, o servidor precisa reagir. Essa reação é conhecida como tratamento de eventos. Quando um usuário carrega a página, o servidor verifica e chama um ou mais event handlers (manipuladores de evento). Assim que esses handlers terminam, eles precisam devolver o controle ao event loop. Para fazer isso em Python, o asyncio usa corrotinas.

Uma corrotina é uma função especial que pode devolver o controle a quem a chamou sem perder o seu estado. Uma corrotina é uma consumidora e uma evolução de um gerador. Uma grande vantagem em relação a threads é que elas consomem bem menos memória para executar. Note que, quando você chama uma função corrotina, ela não executa de imediato. Em vez disso, retorna um objeto corrotina que você pode passar ao event loop para ser executado imediatamente ou depois.

Outro termo que você provavelmente vai encontrar ao usar o módulo asyncio é future. Um future basicamente representa o resultado de um trabalho que ainda não terminou. Seu event loop pode observar objetos future e esperar que eles finalizem. Quando um future termina, ele é marcado como done. O asyncio também oferece suporte a locks e semáforos.

Por fim, vale mencionar a Task. Uma Task é um invólucro (wrapper) para uma corrotina e uma subclasse de Future. Você pode até agendar uma Task usando o event loop.

async e await

As palavras-chave async e await foram adicionadas no Python 3.5 para definir corrotinas nativas e diferenciá-las das corrotinas baseadas em geradores. Se você quiser uma descrição aprofundada de async e await, confira a PEP 492.

No Python 3.4, você criaria uma corrotina assim:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgUHl0aG9uIDMuNCBjb3JvdXRpbmUgZXhhbXBsZVxuIyBJbXBvcnQgYGFzeW5jaW9gXG5pbXBvcnQgX19fX19fX1xuIFxuQGFzeW5jaW8uY29yb3V0aW5lXG5kZWYgbXlfY29ybygpOlxuICAgIHlpZWxkIGZyb20gZnVuYygpIiwic29sdXRpb24iOiIjIFB5dGhvbiAzLjQgY29yb3V0aW5lIGV4YW1wbGVcbmltcG9ydCBhc3luY2lvXG4gXG5AYXN5bmNpby5jb3JvdXRpbmVcbmRlZiBteV9jb3JvKCk6XG4gICAgeWllbGQgZnJvbSBmdW5jKCkiLCJzY3QiOiJFeCgpLnRlc3RfaW1wb3J0KFwiYXN5bmNpb1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJAYXN5bmNpby5jb3JvdXRpbmVcIiwgcGF0dGVybj1GYWxzZSxub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBhZGQgYEBhc3luY2lvLmNvcm91dGluZWAgdG8gdGhlIGNvZGU/XCIpXG5FeCgpLnRlc3RfZnVuY3Rpb25fZGVmaW5pdGlvbihcIm15X2Nvcm9cIilcbnN1Y2Nlc3NfbXNnKFwiWW91IGhhdmUgc3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSBjb3JvdXRpbmUgaW4gUHl0aG9uIDMuNCEgQnV0IHdoYXQgYWJvdXQgbWFraW5nIHRoaXMgY29yb3V0aW5lIGluIFB5dGhvbiAzLjU/XCIpIn0=

Esse decorador ainda funciona no Python 3.5, mas o módulo types recebeu uma atualização com uma função coroutine que agora diz se o que você está usando é uma corrotina nativa ou não. A partir do Python 3.5, você pode usar async def para definir sintaticamente uma função corrotina.

Assim, a função acima ficaria assim:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6ImltcG9ydCBfX19fX19fXG4gXG5hc3luYyBkZWYgX19fX19fXygpOlxuICAgIGF3YWl0IGZ1bmMoKSIsInNvbHV0aW9uIjoiaW1wb3J0IGFzeW5jaW9cbiBcbmFzeW5jIGRlZiBteV9jb3JvKCk6XG4gICAgYXdhaXQgZnVuYygpIiwic2N0IjoiRXgoKS50ZXN0X2ltcG9ydChcImFzeW5jaW9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiYXN5bmMgZGVmIG15X2Nvcm8oKTpcIiwgcGF0dGVybj1GYWxzZSwgbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgZGVmaW5lIHRoZSBhc3luYyBkZWYgZnVuY3Rpb24gYG15X2Nvcm8oKWA/XCIpXG5FeCgpLnRlc3Rfc3R1ZGVudF90eXBlZChcImF3YWl0IGZ1bmMoKVwiLCBwYXR0ZXJuPUZhbHNlLCBub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBhZGQgYGF3YWl0IGZ1bmN0KClgIHRvIHRoZSBhc3luYyBkZWYgZnVuY3Rpb24gYG15X2Nvcm8oKWA/XCIpXG5zdWNjZXNzX21zZyhcIldlbGwgZG9uZSEgWW91IGhhdmUgbm93IGNyZWF0ZWQgYSBjb3JvdXRpbmUgdXNpbmcgUHl0aG9uIDMuNSFcIikifQ==

Ao definir uma corrotina desse jeito, você não pode usar yield dentro da função corrotina. Em vez disso, ela deve incluir uma instrução return ou await, usadas para retornar valores ao chamador. Observe que a palavra-chave await só pode ser usada dentro de uma função async def.

As palavras-chave async/await podem ser vistas como uma API para programação assíncrona. O módulo asyncio é “apenas” um framework que usa async/await para programar de forma assíncrona. Existe inclusive um projeto chamado curio que prova esse conceito, pois implementa um event loop separado que usa async/await por baixo dos panos.

Um exemplo ruim de corrotina

Embora seja útil ter bastante contexto de como tudo isso funciona, às vezes você só quer ver alguns exemplos para entender a sintaxe e como montar as peças.

Com isso em mente, vamos começar com um exemplo simples!

Uma tarefa bem comum é baixar um arquivo de algum lugar, seja um recurso interno ou um arquivo na Internet. Normalmente você vai querer baixar mais de um arquivo.

Então vamos criar um par de corrotinas para fazer isso:

import asyncio
import os
import urllib.request
 
async def download_coroutine(url):
    #"A coroutine to download the specified url"
    request = urllib.request.urlopen(url)
    filename = os.path.basename(url)
 
    with open(filename, 'wb') as file_handle:
        while True:
            chunk = request.read(1024)
            if not chunk:
                break
            file_handle.write(chunk)
    msg = 'Finished downloading {filename}'.format(filename=filename)
    return msg
 
async def main(urls):
    """
    Creates a group of coroutines and waits for them to finish
    """
    coroutines = [download_coroutine(url) for url in urls]
    completed, pending = await asyncio.wait(coroutines)
    for item in completed:
        print(item.result())
 
 
if __name__ == '__main__':
    urls = ["http://www.irs.gov/pub/irs-pdf/f1040.pdf",
            "http://www.irs.gov/pub/irs-pdf/f1040a.pdf",
            "http://www.irs.gov/pub/irs-pdf/f1040ez.pdf",
            "http://www.irs.gov/pub/irs-pdf/f1040es.pdf",
            "http://www.irs.gov/pub/irs-pdf/f1040sb.pdf"]
 
    event_loop = asyncio.get_event_loop()
    try:
        event_loop.run_until_complete(main(urls))
    finally:
        event_loop.close()

Neste código, importamos os módulos necessários e criamos nossa primeira corrotina usando a sintaxe async. Essa corrotina se chama download_coroutine e usa o urllib do Python para baixar qualquer URL passada para ela. Quando termina, retorna uma mensagem avisando.

A outra corrotina é a principal. Ela basicamente recebe uma lista com uma ou mais URLs e as enfileira. Usamos a função wait do asyncio para aguardar as corrotinas terminarem. Claro que, para realmente iniciar as corrotinas, elas precisam ser adicionadas ao event loop. Fazemos isso no final, quando obtemos um event loop e chamamos seu método run_until_complete. Observe que passamos a corrotina principal ao event loop. Isso inicia sua execução, que por sua vez enfileira a segunda corrotina e a dispara. Esse encadeamento é conhecido como chained coroutine.

O problema desse exemplo é que ele na prática não é assíncrono. O motivo é que a função download_coroutine não é assíncrona de verdade. O problema aqui é que o urllib não é assíncrono e, além disso, não estamos usando await nem yield. Uma forma melhor seria usar o pacote aiohttp. Vamos ver isso a seguir!

Um exemplo melhor de corrotina

O pacote aiohttp foi criado para clientes e servidores HTTP assíncronos. Você pode instalá-lo com pip assim:

pip install aiohttp

Depois de instalado, vamos atualizar nosso código para usar o aiohttp e baixar os arquivos:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6ImltcG9ydCBhaW9odHRwXG5pbXBvcnQgYXN5bmNpb1xuaW1wb3J0IGFzeW5jX3RpbWVvdXRcbmltcG9ydCBvc1xuIFxuYXN5bmMgZGVmIGRvd25sb2FkX2Nvcm91dGluZShzZXNzaW9uLCB1cmwpOlxuICAgIHdpdGggYXN5bmNfdGltZW91dC50aW1lb3V0KDEwKTpcbiAgICAgICAgYXN5bmMgd2l0aCBzZXNzaW9uLmdldCh1cmwpIGFzIHJlc3BvbnNlOlxuICAgICAgICAgICAgZmlsZW5hbWUgPSBfXy5wYXRoLmJhc2VuYW1lKHVybClcbiAgICAgICAgICAgIHdpdGggb3BlbihfX19fX19fXywgJ3diJykgYXMgZl9oYW5kbGU6XG4gICAgICAgICAgICAgICAgd2hpbGUgVHJ1ZTpcbiAgICAgICAgICAgICAgICAgICAgY2h1bmsgPSBhd2FpdCByZXNwb25zZS5jb250ZW50LnJlYWQoMTAyNClcbiAgICAgICAgICAgICAgICAgICAgaWYgbm90IGNodW5rOlxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgICAgICAgICAgICAgZl9oYW5kbGUud3JpdGUoX19fX18pXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgcmVzcG9uc2UucmVsZWFzZSgpXG4gXG5hc3luYyBkZWYgbWFpbihsb29wKTpcbiAgICB1cmxzID0gW1wiaHR0cDovL3d3dy5pcnMuZ292L3B1Yi9pcnMtcGRmL2YxMDQwLnBkZlwiLFxuICAgICAgICBcImh0dHA6Ly93d3cuaXJzLmdvdi9wdWIvaXJzLXBkZi9mMTA0MGEucGRmXCIsXG4gICAgICAgIFwiaHR0cDovL3d3dy5pcnMuZ292L3B1Yi9pcnMtcGRmL2YxMDQwZXoucGRmXCIsXG4gICAgICAgIFwiaHR0cDovL3d3dy5pcnMuZ292L3B1Yi9pcnMtcGRmL2YxMDQwZXMucGRmXCIsXG4gICAgICAgIFwiaHR0cDovL3d3dy5pcnMuZ292L3B1Yi9pcnMtcGRmL2YxMDQwc2IucGRmXCJdXG4gXG4gICAgYXN5bmMgd2l0aCBhaW9odHRwLkNsaWVudFNlc3Npb24obG9vcD1sb29wKSBhcyBzZXNzaW9uOlxuICAgICAgICB0YXNrcyA9IFtkb3dubG9hZF9jb3JvdXRpbmUoc2Vzc2lvbiwgdXJsKSBmb3IgdXJsIGluIHVybHNdXG4gICAgICAgIGF3YWl0IGFzeW5jaW8uZ2F0aGVyKCp0YXNrcylcbiBcbmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6XG4gICAgbG9vcCA9IGFzeW5jaW8uZ2V0X2V2ZW50X2xvb3AoKVxuICAgIGxvb3AucnVuX3VudGlsX2NvbXBsZXRlKG1haW4obG9vcCkpIiwic29sdXRpb24iOiJpbXBvcnQgYWlvaHR0cFxuaW1wb3J0IGFzeW5jaW9cbmltcG9ydCBhc3luY190aW1lb3V0XG5pbXBvcnQgb3NcbiBcbmFzeW5jIGRlZiBkb3dubG9hZF9jb3JvdXRpbmUoc2Vzc2lvbiwgdXJsKTpcbiAgICB3aXRoIGFzeW5jX3RpbWVvdXQudGltZW91dCgxMCk6XG4gICAgICAgIGFzeW5jIHdpdGggc2Vzc2lvbi5nZXQodXJsKSBhcyByZXNwb25zZTpcbiAgICAgICAgICAgIGZpbGVuYW1lID0gb3MucGF0aC5iYXNlbmFtZSh1cmwpXG4gICAgICAgICAgICB3aXRoIG9wZW4oZmlsZW5hbWUsICd3YicpIGFzIGZfaGFuZGxlOlxuICAgICAgICAgICAgICAgIHdoaWxlIFRydWU6XG4gICAgICAgICAgICAgICAgICAgIGNodW5rID0gYXdhaXQgcmVzcG9uc2UuY29udGVudC5yZWFkKDEwMjQpXG4gICAgICAgICAgICAgICAgICAgIGlmIG5vdCBjaHVuazpcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrXG4gICAgICAgICAgICAgICAgICAgIGZfaGFuZGxlLndyaXRlKGNodW5rKVxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHJlc3BvbnNlLnJlbGVhc2UoKVxuIFxuYXN5bmMgZGVmIG1haW4obG9vcCk6XG4gICAgdXJscyA9IFtcImh0dHA6Ly93d3cuaXJzLmdvdi9wdWIvaXJzLXBkZi9mMTA0MC5wZGZcIixcbiAgICAgICAgXCJodHRwOi8vd3d3Lmlycy5nb3YvcHViL2lycy1wZGYvZjEwNDBhLnBkZlwiLFxuICAgICAgICBcImh0dHA6Ly93d3cuaXJzLmdvdi9wdWIvaXJzLXBkZi9mMTA0MGV6LnBkZlwiLFxuICAgICAgICBcImh0dHA6Ly93d3cuaXJzLmdvdi9wdWIvaXJzLXBkZi9mMTA0MGVzLnBkZlwiLFxuICAgICAgICBcImh0dHA6Ly93d3cuaXJzLmdvdi9wdWIvaXJzLXBkZi9mMTA0MHNiLnBkZlwiXVxuIFxuICAgIGFzeW5jIHdpdGggYWlvaHR0cC5DbGllbnRTZXNzaW9uKGxvb3A9bG9vcCkgYXMgc2Vzc2lvbjpcbiAgICAgICAgdGFza3MgPSBbZG93bmxvYWRfY29yb3V0aW5lKHNlc3Npb24sIHVybCkgZm9yIHVybCBpbiB1cmxzXVxuICAgICAgICBhd2FpdCBhc3luY2lvLmdhdGhlcigqdGFza3MpXG4gXG4gXG5pZiBfX25hbWVfXyA9PSAnX19tYWluX18nOlxuICAgIGxvb3AgPSBhc3luY2lvLmdldF9ldmVudF9sb29wKClcbiAgICBsb29wLnJ1bl91bnRpbF9jb21wbGV0ZShtYWluKGxvb3ApKSIsInNjdCI6IkN4KCkudGVzdF9pbXBvcnQoXCJhaW9odHRwXCIpXG5FeCgpLnRlc3RfaW1wb3J0KFwiYXN5bmNpb1wiKVxuRXgoKS50ZXN0X2ltcG9ydChcImFzeW5jX3RpbWVvdXRcIilcbkV4KCkudGVzdF9pbXBvcnQoXCJvc1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJhc3luYyBkZWYgZG93bmxvYWRfY29yb3V0aW5lKHNlc3Npb24sIHVybCk6XCIscGF0dGVybj1GYWxzZSwgbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgZGVmaW5lIGBhc3luYyBkZWYgZG93bmxvYWRfY29yb3V0aW5lYCB0aGF0IHRha2VzIGBzZXNzaW9uYCBhbmQgYHVybGAgYXMgYXJndW1lbnRzP1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJ3aXRoIGFzeW5jX3RpbWVvdXQudGltZW91dCgxMClcIiwgcGF0dGVybj1GYWxzZSxub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBzZXQgdGhlIGFzeW5jIHRpbWVvdXQgYXQgYDEwYD9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiYXN5bmMgd2l0aCBzZXNzaW9uLmdldCh1cmwpIGFzIHJlc3BvbnNlOlwiLCBwYXR0ZXJuPUZhbHNlLCBub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBjYWxsIGBzZXNzaW9uYCdzIGBnZXQoKWAgbWV0aG9kIHRvIGdldCB0aGUgYHJlc3BvbnNlYCBvYmplY3QgYmFjaz9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiZmlsZW5hbWUgPSBvcy5wYXRoLmJhc2VuYW1lKHVybClcIixwYXR0ZXJuPUZhbHNlLCBub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBzcGVjaWZ5IHRoZSBgZmlsZW5hbWVgIHZhcmlhYmxlIHdpdGggdGhlIGhlbHAgb2YgYG9zLnBhdGguYmFzZW5hbWUoKWA/XCIpXG5FeCgpLnRlc3Rfc3R1ZGVudF90eXBlZChcIndpdGggb3BlbihmaWxlbmFtZSwgXFwnd2JcXCcpIGFzIGZfaGFuZGxlOlwiLCBwYXR0ZXJuPUZhbHNlLCBub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBwYXNzIGBmaWxlbmFtZWAgYW5kIGAnd2InYCB0byBgb3BlbignKWAgP1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJ3aGlsZSBUcnVlXCIsIHBhdHRlcm49RmFsc2Usbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgbGVhdmUgc29tZXRoaW5nIG91dCBvZiB0aGUgY29kZT9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiY2h1bmsgPSBhd2FpdCByZXNwb25zZS5jb250ZW50LnJlYWQoMTAyNClcIiwgcGF0dGVybj1GYWxzZSwgbm90X3R5cGVkX21zZz1cIkRpZCB5b3Ugc3BlY2lmeSB0aGUgYGNodW5rYCB2YXJpYWJsZT9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiaWYgbm90IGNodW5rXCIsIHBhdHRlcm49RmFsc2Usbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgbGVhdmUgc29tZXRoaW5nIG91dCBvZiB0aGUgY29kZT9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiYnJlYWtcIiwgcGF0dGVybj1GYWxzZSxub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBsZWF2ZSBzb21ldGhpbmcgb3V0IG9mIHRoZSBjb2RlP1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJmX2hhbmRsZS53cml0ZShjaHVuaylcIiwgcGF0dGVybj1GYWxzZSxub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBwYXNzIGBjaHVua2AgdG8gYGZfaGFuZGxlLndyaXRlKClgP1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJyZXR1cm4gYXdhaXQgcmVzcG9uc2UucmVsZWFzZSgpXCIsIHBhdHRlcm49RmFsc2Usbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgbGVhdmUgc29tZXRoaW5nIG91dCBvZiB0aGUgY29kZT9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiYXN5bmMgZGVmIG1haW4obG9vcCk6XCIsIHBhdHRlcm49RmFsc2Usbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgbGVhdmUgc29tZXRoaW5nIG91dCBvZiB0aGUgY29kZT9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwidXJscyA9IFtcXFwiaHR0cDovL3d3dy5pcnMuZ292L3B1Yi9pcnMtcGRmL2YxMDQwLnBkZlxcXCIsXCIscGF0dGVybj1GYWxzZSwgbm90X3R5cGVkX21zZz1cIk1ha2Ugc3VyZSB0byBwYXNzIGF0IGxlYXN0IDEgdXJsIHRvIHRoZSBgdXJsc2AgdmFyaWFibGUhXCIpXG5FeCgpLnRlc3Rfc3R1ZGVudF90eXBlZChcIlxcXCJdXCIsIHBhdHRlcm49RmFsc2UsKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJhc3luYyB3aXRoIGFpb2h0dHAuQ2xpZW50U2Vzc2lvbihsb29wPWxvb3ApIGFzIHNlc3Npb246XCIsIHBhdHRlcm49RmFsc2UsIG5vdF90eXBlZF9tc2c9XCJEaWQgeW91IGxlYXZlIHNvbWV0aGluZyBvdXQgb2YgdGhlIGNvZGU/XCIpXG5FeCgpLnRlc3Rfc3R1ZGVudF90eXBlZChcInRhc2tzID0gW2Rvd25sb2FkX2Nvcm91dGluZShzZXNzaW9uLCB1cmwpIGZvciB1cmwgaW4gdXJsc11cIiwgcGF0dGVybj1GYWxzZSxub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBsZWF2ZSBzb21ldGhpbmcgb3V0IG9mIHRoZSBjb2RlP1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJhd2FpdCBhc3luY2lvLmdhdGhlcigqdGFza3MpXCIsIHBhdHRlcm49RmFsc2Usbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgbGVhdmUgc29tZXRoaW5nIG91dCBvZiB0aGUgY29kZT9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiaWYgX19uYW1lX18gPT0gXFwnX19tYWluX19cXCc6XCIsIHBhdHRlcm49RmFsc2Usbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgbGVhdmUgc29tZXRoaW5nIG91dCBvZiB0aGUgY29kZT9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwibG9vcCA9IGFzeW5jaW8uZ2V0X2V2ZW50X2xvb3AoKVwiLCBwYXR0ZXJuPUZhbHNlLG5vdF90eXBlZF9tc2c9XCJEaWQgeW91IGluaXRpYWxpemUgYSBgbG9vcGAgb2JqZWN0P1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJsb29wLnJ1bl91bnRpbF9jb21wbGV0ZShtYWluKGxvb3ApKVwiLCBwYXR0ZXJuPUZhbHNlLG5vdF90eXBlZF9tc2c9XCJEaWQgeW91IGxlYXZlIHNvbWV0aGluZyBvdXQgb2YgdGhlIGNvZGU/XCIpXG5zdWNjZXNzX21zZyhcIldlbGwgZG9uZSEgWW91IGhhdmUgbm93IGRvd25sb2FkZWQgdGhlIGZpbGVzIHdpdGggdGhlIGBhaW9odHRwYCBwYWNrYWdlIVwiKSJ9

Você vai notar que importamos dois itens novos: aiohttp e async_timeout. O segundo é, na verdade, uma dependência do aiohttp e permite criar um context manager de timeout. Vamos começar pelo final do código e ir subindo. No condicional do final, iniciamos nosso event loop assíncrono e chamamos a função principal.

Na função principal, criamos um objeto ClientSession e o passamos para nossa função corrotina de download para cada uma das URLs que queremos baixar. Na download_coroutine, criamos um context manager async_timeout.timeout() que basicamente cria um temporizador de X segundos. Quando o tempo acaba, o context manager termina (ou dá timeout). Aqui, o limite é de 10 segundos. Em seguida, chamamos o método get() da sessão, que nos dá um objeto de resposta. Agora vem a parte “mágica”: ao usar o atributo content do objeto de resposta, recebemos uma instância de aiohttp.StreamReader, que permite baixar o arquivo em blocos do tamanho que quisermos. Conforme lemos o arquivo, gravamos no disco local. Por fim, chamamos o método release() da resposta, que finaliza o processamento.

Segundo a documentação do aiohttp, como o objeto de resposta foi criado dentro de um context manager, tecnicamente o release() é chamado implicitamente. Mas, em Python, o explícito costuma ser melhor, e há uma nota na documentação indicando que não devemos contar com a conexão simplesmente sumindo. Então, neste caso, acho melhor chamar o release explicitamente.

Há uma parte que ainda é bloqueante: a gravação em disco. Enquanto escrevemos o arquivo, ainda bloqueamos. Existe outra biblioteca, a aiofiles, que poderíamos usar para tornar a escrita de arquivos assíncrona também, mas vou deixar essa melhoria para você.

Agendando chamadas

Você também pode agendar chamadas a funções “normais” usando o event loop do asyncio. O primeiro método que vamos ver é o call_soon. Ele basicamente chama seu callback ou event handler assim que possível. Ele funciona como uma fila FIFO, então, se alguns callbacks demorarem para rodar, os demais serão atrasados até que os anteriores terminem.

Vamos ver um exemplo:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6ImltcG9ydCBfX19fX19cbmltcG9ydCBmdW5jdG9vbHNcbiBcbmRlZiBldmVudF9oYW5kbGVyKGxvb3AsIHN0b3A9RmFsc2UpOlxuICAgIHByaW50KCdFdmVudCBoYW5kbGVyIGNhbGxlZCcpXG4gICAgaWYgc3RvcDpcbiAgICAgICAgcHJpbnQoJ3N0b3BwaW5nIHRoZSBsb29wJylcbiAgICAgICAgbG9vcC5zdG9wKClcblxuaWYgX19uYW1lX18gPT0gJ19fbWFpbl9fJzpcbiAgICBsb29wID0gYXN5bmNpby5nZXRfZXZlbnRfbG9vcCgpXG4gICAgdHJ5OlxuICAgICAgICBsb29wLmNhbGxfc29vbihmdW5jdG9vbHMucGFydGlhbChfX19fX19fX19fX19fLCBfX19fKSlcbiAgICAgICAgcHJpbnQoJ3N0YXJ0aW5nIGV2ZW50IGxvb3AnKVxuICAgICAgICBsb29wLmNhbGxfc29vbihmdW5jdG9vbHMucGFydGlhbChfX19fX19fX19fX19fLCBfX19fLCBzdG9wPVRydWUpKVxuIFxuICAgICAgICBsb29wLl9fX19fX19fX18oKVxuICAgIGZpbmFsbHk6XG0gICAgICAgIHByaW50KCdjbG9zaW5nIGV2ZW50IGxvb3AnKVxuICAgICAgICBsb29wLl9fX19fKCkiLCJzb2x1dGlvbiI6ImltcG9ydCBhc3luY2lvXG5pbXBvcnQgZnVuY3Rvb2xzXG4gXG5kZWYgZXZlbnRfaGFuZGxlcihsb29wLCBzdG9wPUZhbHNlKTpcbiAgICBwcmludCgnRXZlbnQgaGFuZGxlciBjYWxsZWQnKVxuICAgIGlmIHN0b3A6XG4gICAgICAgIHByaW50KCdzdG9wcGluZyB0aGUgbG9vcCcpXG4gICAgICAgIGxvb3Auc3RvcCgpXG5cbmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6XG4gICAgbG9vcCA9IGFzeW5jaW8uZ2V0X2V2ZW50X2xvb3AoKVxuICAgIHRyeTpcbiAgICAgICAgbG9vcC5jYWxsX3Nvb24oZnVuY3Rvb2xzLnBhcnRpYWwoZXZlbnRfaGFuZGxlciwgbG9vcCkpXG4gICAgICAgIHByaW50KCdzdGFydGluZyBldmVudCBsb29wJylcbiAgICAgICAgbG9vcC5jYWxsX3Nvb24oZnVuY3Rvb2xzLnBhcnRpYWwoZXZlbnRfaGFuZGxlciwgbG9vcCwgc3RvcD1UcnVlKSlcbiBcbiAgICAgICAgbG9vcC5ydW5fZm9yZXZlcigpXG4gICAgZmluYWxseTpcbiAgICAgICAgcHJpbnQoJ2Nsb3NpbmcgZXZlbnQgbG9vcCcpXG4gICAgICAgIGxvb3AuY2xvc2UoKSIsInNjdCI6IkV4KCkudGVzdF9pbXBvcnQoXCJhc3luY2lvXCIpXG5FeCgpLnRlc3RfaW1wb3J0KFwiZnVuY3Rvb2xzXCIpXG5FeCgpLnRlc3RfZnVuY3Rpb25fZGVmaW5pdGlvbihcImV2ZW50X2hhbmRsZXJcIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiaWYgX19uYW1lX18gPT0gXFwnX19tYWluX19cXCc6XCIsIHBhdHRlcm49RmFsc2UsIG5vdF90eXBlZF9tc2c9XCJEaWQgeW91IHJlbW92ZSBzb21ldGhpbmcgZnJvbSB0aGUgY29kZTE/XCIpXG5FeCgpLnRlc3Rfc3R1ZGVudF90eXBlZChcImxvb3AgPSBhc3luY2lvLmdldF9ldmVudF9sb29wKClcIiwgcGF0dGVybj1GYWxzZSxub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBhc3NpZ24gYGFzeW5jaW8uZ2V0X2V2ZW50X2xvb3AoKWAgdG8gYGxvb3BgP1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJ0cnk6XCIsIHBhdHRlcm49RmFsc2Usbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgYWRkIGB0cnlgIHRvIHRoZSBjb2RlP1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJsb29wLmNhbGxfc29vbihmdW5jdG9vbHMucGFydGlhbChldmVudF9oYW5kbGVyLCBsb29wKSlcIiwgcGF0dGVybj1GYWxzZSwgbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgcGFzcyBgZXZlbnRfaGFuZGxlcmAgYW5kIGBsb29wYCB0byBgbG9vcC5jYWxsX3Nvb24oZnVuY3Rvb2xzLnBhcnRpYWwoKSlgP1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJsb29wLmNhbGxfc29vbihmdW5jdG9vbHMucGFydGlhbChldmVudF9oYW5kbGVyLCBsb29wLCBzdG9wPVRydWUpKVwiLCBwYXR0ZXJuPUZhbHNlLCBub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBwYXNzIGBldmVudF9oYW5kbGVyYCBhbmQgYGxvb3BgIHRvIGBsb29wLmNhbGxfc29vbihmdW5jdG9vbHMucGFydGlhbCgpKWA/IERvbid0IGZvcmdldCB0byBrZWVwIGBzdG9wYCBzZXQgdG8gYFRydWVgIVwiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJsb29wLnJ1bl9mb3JldmVyKClcIiwgcGF0dGVybj1GYWxzZSxub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBhZGQgYGxvb3AucnVuX2ZvcmV2ZXIoKWAgdG8gdGhlIGNvZGU/XCIpXG5FeCgpLnRlc3Rfc3R1ZGVudF90eXBlZChcImZpbmFsbHk6XCIsIHBhdHRlcm49RmFsc2Usbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgYWRkIGBmaW5hbGx5YCB0byB0aGUgY29kZT9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwibG9vcC5jbG9zZSgpXCIsIHBhdHRlcm49RmFsc2Usbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgY2xvc2UgYGxvb3BgP1wiKVxuc3VjY2Vzc19tc2coXCJZb3UgaGF2ZSBub3cgc3VjY2Vzc2Z1bGx5IGxlYXJuZWQgaG93IHRvIHNjaGVkdWxlIGNhbGxzIHdpdGggdGhlIGFzeW5jaW8gZXZlbnQgbG9vcCFcIikifQ==

A maioria das funções do asyncio não aceita argumentos nomeados, então precisamos do módulo functools se quisermos passar keywords para nosso handler. Nossa função “normal” imprime um texto no stdout sempre que é chamada. Se você definir o argumento stop como True, ela também para o event loop.

Na primeira chamada, não paramos o loop. Na segunda chamada, paramos. Fazemos isso porque usamos run_forever, que coloca o event loop em um laço infinito. Quando o loop é interrompido, podemos fechá-lo.

Ao rodar esse código, você deverá ver a seguinte saída:

starting event loop
Event handler called
Event handler called
stopping the loop
closing event loop

Existe uma função relacionada chamada call_soon_threadsafe. Como o nome indica, ela funciona como a call_soon, mas é thread-safe. Se você quiser adiar uma chamada para algum momento no futuro, pode usar a função call_later. Neste caso, poderíamos trocar a assinatura de call_soon por:

loop.call_later(1, event_handler, loop)

Isso vai atrasar a chamada do nosso event handler por um segundo, e então chamá-lo passando o loop como primeiro parâmetro. Se quiser agendar um horário específico no futuro, é melhor usar a noção de tempo do próprio loop, e não a do computador. Você pode fazer assim:

current_time = loop.time()

Com isso em mãos, basta usar a função call_at e passar o horário em que você quer que o handler seja chamado. Suponha que queremos chamá-lo daqui a cinco minutos. Ficaria assim:

loop.call_at(current_time + 300, event_handler, loop)

Neste exemplo, usamos o horário atual do loop e somamos 300 segundos (cinco minutos). Assim, adiamos a chamada do nosso event handler por cinco minutos. Legal, né?

Tasks

Tasks são uma subclasse de Future e um wrapper em torno de uma corrotina. Elas permitem que você acompanhe quando o processamento termina. Por serem um tipo de Future, outras corrotinas podem aguardar uma task, e você também pode obter o resultado de uma task quando ela terminar.

Vamos ver um exemplo simples:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6ImltcG9ydCBfX19fX19fXG5cbmFzeW5jIGRlZiBteV90YXNrKHNlY29uZHMpOlxuICAgIFwiXCJcIlxuICAgIEEgdGFzayB0byBkbyBmb3IgYSBudW1iZXIgb2Ygc2Vjb25kc1xuICAgIFwiXCJcIlxuICAgIHByaW50KCdUaGlzIHRhc2sgaXMgdGFraW5nIHt9IHNlY29uZHMgdG8gY29tcGxldGUnLmZvcm1hdChcbiAgICAgICAgc2Vjb25kcykpXG4gICAgYXdhaXQgYXN5bmNpby5zbGVlcChfX19fX19fKVxuICAgIHJldHVybiAndGFzayBmaW5pc2hlZCdcbiBcbiBcbmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6XG4gICAgbXlfZXZlbnRfbG9vcCA9IGFzeW5jaW8uZ2V0X2V2ZW50X2xvb3AoKVxuICAgIHRyeTpcbiAgICAgICAgcHJpbnQoJ3Rhc2sgY3JlYXRpb24gc3RhcnRlZCcpXG4gICAgICAgIHRhc2tfb2JqID0gbXlfZXZlbnRfbG9vcC5jcmVhdGVfdGFzayhteV90YXNrKHNlY29uZHM9MikpXG4gICAgICAgIG15X2V2ZW50X2xvb3AucnVuX3VudGlsX2NvbXBsZXRlKHRhc2tfb2JqKVxuICAgIGZpbmFsbHk6XG4gICAgICAgIG15X2V2ZW50X2xvb3AuX19fX18oKVxuIFxuICAgIHByaW50KFwiVGhlIHRhc2sncyByZXN1bHQgd2FzOiB7fVwiLmZvcm1hdCh0YXNrX29iai5yZXN1bHQoKSkpIiwic29sdXRpb24iOiJpbXBvcnQgYXN5bmNpb1xuXG5hc3luYyBkZWYgbXlfdGFzayhzZWNvbmRzKTpcbiAgICBcIlwiXCJcbiAgICBBIHRhc2sgdG8gZG8gZm9yIGEgbnVtYmVyIG9mIHNlY29uZHNcbiAgICBcIlwiXCJcbiAgICBwcmludCgnVGhpcyB0YXNrIGlzIHRha2luZyB7fSBzZWNvbmRzIHRvIGNvbXBsZXRlJy5mb3JtYXQoc2Vjb25kcykpXG4gICAgYXdhaXQgYXN5bmNpby5zbGVlcChzZWNvbmRzKVxuICAgIHJldHVybiAndGFzayBmaW5pc2hlZCdcbiBcbiBcbmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6XG4gICAgbXlfZXZlbnRfbG9vcCA9IGFzeW5jaW8uZ2V0X2V2ZW50X2xvb3AoKVxuICAgIHRyeTpcbiAgICAgICAgcHJpbnQoJ3Rhc2sgY3JlYXRpb24gc3RhcnRlZCcpXG4gICAgICAgIHRhc2tfb2JqID0gbXlfZXZlbnRfbG9vcC5jcmVhdGVfdGFzayhteV90YXNrKHNlY29uZHM9MikpXG4gICAgICAgIG15X2V2ZW50X2xvb3AucnVuX3VudGlsX2NvbXBsZXRlKHRhc2tfb2JqKVxuICAgIGZpbmFsbHk6XG4gICAgICAgIG15X2V2ZW50X2xvb3AuY2xvc2UoKVxuIFxuICAgIHByaW50KFwiVGhlIHRhc2sncyByZXN1bHQgd2FzOiB7fVwiLmZvcm1hdCh0YXNrX29iai5yZXN1bHQoKSkpIiwic2N0IjoiRXgoKS50ZXN0X2ltcG9ydChcImFzeW5jaW9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiYXN5bmMgZGVmIG15X3Rhc2soc2Vjb25kcyk6XCIsIHBhdHRlcm49RmFsc2UsIG5vdF90eXBlZF9tc2c9XCJEaWQgeW91IGRlZmluZSB0aGUgYXN5bmMgZnVuY3Rpb24gYG15X3Rhc2soKWA/XCIpXG5FeCgpLnRlc3Rfc3R1ZGVudF90eXBlZChcImF3YWl0IGFzeW5jaW8uc2xlZXAoc2Vjb25kcylcIiwgcGF0dGVybj1GYWxzZSwgbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgcGFzcyBgc2Vjb25kc2AgdG8gYGFzeW5jaW8uc2xlZXAoKWA/XCIpXG5FeCgpLnRlc3Rfc3R1ZGVudF90eXBlZChcInJldHVybiBcXCd0YXNrIGZpbmlzaGVkXFwnXCIsIHBhdHRlcm49RmFsc2UsIG5vdF90eXBlZF9tc2c9XCJEaWQgeW91IHJldHVybiBcXCd0YXNrIGZpbmlzaGVkXFwnP1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJpZiBfX25hbWVfXyA9PSBcXCdfX21haW5fX1xcJzpcIiwgcGF0dGVybj1GYWxzZSwgbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgcmVtb3ZlIHNvbWV0aGluZyBmcm9tIHRoZSBjb2RlP1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJteV9ldmVudF9sb29wID0gYXN5bmNpby5nZXRfZXZlbnRfbG9vcCgpXCIsIHBhdHRlcm49RmFsc2UsIG5vdF90eXBlZF9tc2c9XCJEaWQgeW91IGdldCB0aGUgZXZlbnQgbG9vcCB3aXRoIGBnZXRfZXZlbnRfbG9vcCgpYCBhbmQgYXNzaWduIGl0IHRvIGBteV9ldmVudF9sb29wYD9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwidHJ5OlwiLCBwYXR0ZXJuPUZhbHNlLCBub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBhZGQgYHRyeWAgdG8gdGhlIGNvZGUgY2h1bms/XCIpXG5FeCgpLnRlc3Rfc3R1ZGVudF90eXBlZChcInRhc2tfb2JqID0gbXlfZXZlbnRfbG9vcC5jcmVhdGVfdGFzayhteV90YXNrKHNlY29uZHM9MikpXCIsIHBhdHRlcm49RmFsc2UsIG5vdF90eXBlZF9tc2c9XCJEaWQgeW91IGNyZWF0ZSBhIHRhc2sgZm9yIGBteV9ldmVudF9sb29wYCB3aXRoIGBjcmVhdGVfdGFza2A/IEFsc28gZG9uJ3QgZm9yZ2V0IHRvIHBhc3MgYG15X3Rhc2soc2Vjb25kcz0yKWAgdG8gdGhlIGZ1bmN0aW9uIVwiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJteV9ldmVudF9sb29wLnJ1bl91bnRpbF9jb21wbGV0ZSh0YXNrX29iailcIiwgcGF0dGVybj1GYWxzZSwgbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgYWRkIGBteV9ldmVudF9sb29wLnJ1bl91bnRpbF9jb21wbGV0ZSh0YXNrX29iaikgdG8gdGhlIGNvZGUgY2h1bms/XCIpXG5FeCgpLnRlc3Rfc3R1ZGVudF90eXBlZChcImZpbmFsbHk6XCIsIHBhdHRlcm49RmFsc2UsIG5vdF90eXBlZF9tc2c9XCJEaWQgeW91IHNwZWNpZnkgYGZpbmFsbHlgP1wiKVxuRXgoKS50ZXN0X3N0dWRlbnRfdHlwZWQoXCJteV9ldmVudF9sb29wLmNsb3NlKClcIiwgcGF0dGVybj1GYWxzZSwgbm90X3R5cGVkX21zZz1cIkRpZCB5b3UgY2xvc2UgYG15X2V2ZW50X2xvb3BgIHdpdGggYGNsb3NlKClgP1wiKVxuc3VjY2Vzc19tc2coXCJDb25ncmF0cyEgWW91IGhhdmUgY3JlYXRlZCBhbiBhc3luYyBmdW5jdGlvbiB0aGF0IGFjY2VwdHMgdGhlIG51bWJlciBvZiBzZWNvbmRzIGl0IHdpbGwgdGFrZSBmb3IgdGhlIGZ1bmN0aW9uIHRvIHJ1biFcIikifQ==

Aqui criamos uma função assíncrona que recebe o número de segundos que a função vai levar para rodar. Isso simula um processo demorado. Em seguida, criamos o event loop e um objeto task chamando a função create_task do event loop. A create_task recebe a função que queremos transformar em task. Depois, pedimos ao event loop que rode até a task terminar. No final, obtemos o resultado da task, já que ela finalizou.

Tasks também podem ser canceladas facilmente com seu método cancel. É só chamá-lo quando quiser encerrar uma task. Se uma task for cancelada enquanto aguarda outra operação, ela lançará um CancelledError.

Fechando

A esta altura, você já sabe o suficiente para começar a trabalhar com a biblioteca asyncio por conta própria. Ela é bem poderosa e permite fazer muita coisa interessante. A biblioteca asyncio foi projetada para sockets de rede.

Uma ótima biblioteca que permite programação assíncrona com sockets antes do asyncio é o framework Twisted. Outro projeto interessante é o Dask, uma biblioteca flexível de computação paralela para análises. Vale explorar a documentação do módulo asyncio e deixar as ideias fluírem!

Tópicos
Python

Cursos de Python

Curso

Introdução ao Python

4 h
7M
Domine os fundamentos da análise de dados com Python em quatro horas e explore pacotes populares.
Ver detalhesRight Arrow
Iniciar Curso
Ver maisRight Arrow
Relacionado

Tutorial

Tutorial FastAPI: Uma introdução ao uso da FastAPI

Explore a estrutura FastAPI e descubra como você pode usá-la para criar APIs em Python
Moez Ali's photo

Moez Ali

13 min

Tutorial

Tutorial de lambda em Python

Aprenda uma maneira mais rápida de escrever funções em tempo real com as funções lambda.
DataCamp Team's photo

DataCamp Team

3 min

Tutorial

Otimização em Python: Técnicas, pacotes e práticas recomendadas

Este artigo ensina a você sobre otimização numérica, destacando diferentes técnicas. Ele discute os pacotes Python, como SciPy, CVXPY e Pyomo, e fornece um notebook DataLab prático para você executar exemplos de código.
Kurtis Pykes 's photo

Kurtis Pykes

11 min

Tutorial

Tutorial sobre loops em Python

Um tutorial introdutório completo sobre loops em Python. Aprenda e pratique loops while e for, loops aninhados, as palavras-chave break e continue, a função range e muito mais!
Satyabrata Pal's photo

Satyabrata Pal

15 min

Tutorial

Desenvolvimento backend com Python: guia completo para iniciantes

Este guia completo ensina os fundamentos do desenvolvimento backend com Python. Aprenda conceitos básicos, frameworks e boas práticas para começar a criar aplicações web.
Oluseye Jeremiah's photo

Oluseye Jeremiah

15 min

Tutorial

Introdução ao Q-learning: um tutorial para iniciantes

Aprenda o algoritmo de aprendizado por reforço sem modelo mais popular com um tutorial em Python.
Abid Ali Awan's photo

Abid Ali Awan

11 min

Ver MaisVer Mais