CodeGym /Curso Java /Python SELF PT /Métodos Assíncronos

Métodos Assíncronos

Python SELF PT
Nível 25 , Lição 2
Disponível

3.1 Módulo asyncio

Já faz tempo que ninguém cria suas próprias threads para tarefas assíncronas. Quer dizer, dá pra criar, mas essas ações são consideradas muito de baixo nível e só são usadas por desenvolvedores de frameworks. E isso quando realmente não tem outro jeito.

Agora tá na moda programação assíncrona, operadores async/await e corrotinas com tasks. Mas vamos por partes...

Um pouco de história

Inicialmente, no Python, para resolver problemas de programação assíncrona eram usadas corrotinas, baseadas em geradores. Depois, no Python 3.4, surgiu o módulo asyncio (às vezes chamado de async IO), que implementa mecanismos de programação assíncrona. No Python 3.5, apareceu a construção async/await.

Agora um pouco sobre o contexto. Primeiro eu vou falar brevemente sobre todas essas coisas, depois com mais detalhes, e depois ainda mais detalhes. Não dá pra fazer diferente, porque quase todas elas funcionam juntas, e explicar em detalhe o funcionamento de uma sem fazer referência às outras não vai rolar.

Módulo asyncio

O módulo asyncio é destinado à escrita de programas assíncronos, proporcionando a possibilidade de executar tarefas em paralelo. Ele suporta operações assíncronas de entrada-saída, timers, sockets, execução de corrotinas e multithreading, funcionando em um ou mais loops de eventos.

Corrotinas (Coroutines)

Corrotinas são funções assíncronas definidas com a palavra-chave async def. Corrotinas permitem suspender sua execução com a palavra-chave await, o que permite a execução de outras corrotinas nesse meio tempo.


import asyncio

# Definição de uma função assíncrona (corrotina)
async def main():
    print('Hello ...')
    # Suspendemos a execução por 1 segundo
    await asyncio.sleep(1)
    print('... World!')

# Execução da função assíncrona main() no loop de eventos
asyncio.run(main())

Loop de Eventos (Event Loop)

O loop de eventos gerencia a execução de corrotinas, tasks e outras operações assíncronas. Chamar asyncio.run() inicia o loop de eventos e executa a corrotina até a conclusão.


import asyncio

async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')

# Obtenção do loop de eventos atual
loop = asyncio.get_event_loop()
# Execução da corrotina até a conclusão
loop.run_until_complete(main())
# Fechamento do loop de eventos após a conclusão de todas as tarefas
loop.close()

Tasks (Tasks)

Tasks permitem executar corrotinas em paralelo. Criadas com asyncio.create_task() ou asyncio.ensure_future().


import asyncio

# Definição de uma corrotina que será executada com atraso
async def say_after(delay, what):
    # Suspendemos a execução pelo tempo especificado
    await asyncio.sleep(delay)
    print(what)

# Corrotina principal
async def main():
    # Criamos tarefas para execução paralela de corrotinas
    task1 = asyncio.create_task(say_after(1, 'hello'))
    task2 = asyncio.create_task(say_after(2, 'world'))
    
    # Aguardamos a conclusão de ambas as tarefas
    await task1
    await task2

# Execução da corrotina principal
asyncio.run(main())

Futures (Futures)

Objetos Future representam os resultados de operações assíncronas, que estarão disponíveis no futuro. Por exemplo, são usados para aguardar a conclusão de uma tarefa assíncrona.


import asyncio

# Definição de uma corrotina que simula uma tarefa longa
async def long_running_task():
    print('Task started')
    # Suspendemos a execução por 3 segundos
    await asyncio.sleep(3)
    print('Task finished')
    return 'Result'

# Corrotina principal
async def main():
    # Criamos um future para esperar a conclusão da tarefa
    future = asyncio.ensure_future(long_running_task())
    # Aguardamos a conclusão da tarefa e obtemos o resultado
    result = await future  
    print(f'Task result: {result}')

# Execução da corrotina principal
asyncio.run(main())

3.2 Função Assíncrona — async def

Uma função assíncrona é declarada do mesmo jeito que uma função comum, mas antes da palavra-chave def você deve escrever a palavra async.


async def NomeDaFuncao(parametros):
    código da função

Uma função assíncrona é declarada como uma normal, chamada como uma normal, mas o resultado que ela retorna é diferente. Se você chamar uma função assíncrona, ela vai retornar não o resultado, mas um objeto especial — corrotina.

Dá até pra testar isso:


import asyncio

async def main():
    print("Hello World")
            
# Chamada de uma função assíncrona, que retorna uma corrotina
result = main()
# Verificamos o tipo do resultado
print(type(result)) # <class 'coroutine'>

O que acontece? Quando você marca uma função com o async, você na verdade adiciona um decorador a ela, que faz algo mais ou menos assim:


def async_decorator(func):
    # Criamos um objeto Task
    task = Task()
    # Passamos nossa função func para ele executar
    task.target = func  
    # Adicionamos o objeto task na fila de tarefas — Event Loop
    eventloop.add_task(task)  
    # Retornamos o objeto task
    return task 

E seu código fica parecido com:


import asyncio

@async_decorator
def main():
    print("Hello World")
            
result = main()
print(type(result)) # <class 'coroutine'>

O sentido dessa analogia é o seguinte:

Quando você chama a função assíncrona, cria-se um objeto especial Task, que vai executar sua função, mas em algum momento no futuro. Pode ser em 0.0001 seg, ou pode ser em 10.

Esse objeto task é imediatamente retornado como resultado da chamada da sua função assíncrona. Isso é uma corrotina. Sua função assíncrona pode nem ter começado a ser executada ainda, mas o objeto task (corrotina) você já tem.

Pra que serve esse task (corrotina)? Você não pode fazer muita coisa com ele, mas pode fazer 3 coisas:

  • Esperar até que a função assíncrona termine de executar.
  • Esperar até que a função assíncrona termine de executar e obter o resultado da execução da corrotina.
  • Esperar até que 10 (ou qualquer número) de funções assíncronas terminem de executar.

Como fazer isso, eu vou te contar abaixo.

3.3 Operador await

A maior parte das ações com corrotinas começa com "esperar pela execução da função assíncrona". Por isso, para essa ação temos um operador especial await.

Você só precisa escrevê-lo antes da corrotina:


await corrotina

Ou direto antes da chamada da função assíncrona:


await funcao_assincrona(argumentos)

Quando o Python encontra no código o operador await, ele suspende a execução da função atual e espera até que a corrotina termine de executar — até que a função assíncrona referenciada pela corrotina não seja concluída.

Importante! O operador await é usado somente dentro de uma função assíncrona para suspender a execução até que outra corrotina ou operação assíncrona termine.

Isso é feito para simplificar o processo de alternar entre as chamadas de funções assíncronas. Essa chamada await é na verdade uma declaração "vamos esperar aqui por um tempo desconhecido — tratem de executar outras funções assíncronas".

Exemplo:


import asyncio

# Definição de uma função assíncrona
async def async_print(text):
    print(text)
        
# Função assíncrona principal
async def main():
    # Usamos await para aguardar a execução da função assíncrona
    await async_print("Hello World")
        
# Inicia o loop de eventos principal e executa a corrotina main()
asyncio.run(main()) #executa a função assíncrona

Na verdade, o operador await funciona de forma ainda mais inteligente — ele também retorna o resultado da execução da função assíncrona onde foi chamado.

Exemplo:


import asyncio

# Definição de uma função assíncrona que soma dois números
async def async_add(a, b):
    return a + b
        
# Função assíncrona principal
async def main():
    # Usamos await para obter o resultado da execução de async_add
    sum = await async_add(100, 200)
    print(sum)
        
# Inicia o loop de eventos principal e executa a corrotina main()
asyncio.run(main()) #executa a função assíncrona

Então, resumindo, o operador await:

  • Suspende a função assíncrona atual até que outra corrotina ou operação assíncrona termine.
  • Retorna o resultado da operação assíncrona ou corrotina.
  • Pode ser usado somente dentro de uma função assíncrona.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION