Python assíncio.create_task()

Resumo : neste tutorial, você aprenderá como usar asyncio.create_task()a função para executar várias tarefas simultaneamente.

Simulando uma operação de longa duração

Para simular uma operação de longa duração, você pode usar a sleep()corrotina do asynciopacote. A sleep()função atrasa um número especificado de segundos:

await asyncio.sleep(seconds)Linguagem de código:  Python  ( python )

Por sleep()ser uma corrotina, você precisa usar a awaitpalavra-chave. Por exemplo, o seguinte usa a sleep()corrotina para simular uma chamada de API:

import asyncio


async def call_api(message, result=1000, delay=3):
    print(message)
    await asyncio.sleep(delay)
    return resultLinguagem de código:  Python  ( python )

É call_api()uma rotina. Ele exibe uma mensagem, pausa um número especificado de segundos (o padrão é três segundos) e retorna um resultado.

O programa a seguir usa call_api()duas vezes e mede o tempo que leva para ser concluído:

import asyncio
import time


async def call_api(message, result=1000, delay=3):
    print(message)
    await asyncio.sleep(delay)
    return result


async def main():
    start = time.perf_counter()

    price = await call_api('Get stock price of GOOG...', 300)
    print(price)

    price = await call_api('Get stock price of APPL...', 400)
    print(price)

    end = time.perf_counter()
    print(f'It took {round(end-start,0)} second(s) to complete.')

asyncio.run(main())Linguagem de código:  Python  ( python )

Saída:

Get stock price of GOOG...
300
Get stock price of APPL...
400
It took 6.0 second(s) to complete.Linguagem de código:  Python  ( python )

Como funciona (com foco na main()corrotina):

Primeiro, inicie um cronômetro para medir o tempo usando a perf_counter()função do timemódulo:

 start = time.perf_counter()Linguagem de código:  Python  ( python )

Segundo, chame a call_api()corrotina e exiba o resultado:

price = await call_api('Get stock price of GOOG...', 300)
print(price)Linguagem de código:  Python  ( python )

Terceiro, ligue pela call_api()segunda vez:

price = await call_api('Get stock price of APPL...', 400)
print(price)Linguagem de código:  Python  ( python )

Por fim, mostre o tempo que o programa leva para ser concluído:

end = time.perf_counter()
print(f'It took {round(end-start,0)} second(s) to complete.')Linguagem de código:  Python  ( python )

Porque cada um call_api()leva três segundos e chamá-lo duas vezes leva seis segundos.

Neste exemplo, chamamos uma corrotina diretamente e não a colocamos no loop de eventos para execução. Em vez disso, obtemos um objeto de rotina e usamos a awaitpalavra-chave para executá-lo e obter um resultado.

A imagem a seguir ilustra o fluxo de execução do programa:

Python create_task de forma assíncrona

Em outras palavras, usamos asynce awaitpara escrever código assíncrono, mas não podemos executá-lo simultaneamente. Para executar múltiplas operações simultaneamente, precisaremos usar algo chamado tarefas.

Introdução às tarefas Python

Uma tarefa é um wrapper de uma corrotina que agenda a corrotina para ser executada no loop de eventos o mais rápido possível.

O agendamento e a execução ocorrem de maneira não bloqueante. Em outras palavras, você pode criar uma tarefa e executar outro código instantaneamente enquanto a tarefa está em execução.

Observe que a tarefa é diferente da awaitpalavra-chave que bloqueia toda a corrotina até que a operação seja concluída com um resultado.

É importante que você possa criar diversas tarefas e agendá-las para serem executadas instantaneamente no loop de eventos ao mesmo tempo.

Para criar uma tarefa, você passa uma corrotina para a create_task()função do asynciopacote. A create_task()função retorna um Taskobjeto.

O programa a seguir ilustra como criar duas tarefas que agendam e executam a call_api()corrotina:

import asyncio
import time


async def call_api(message, result=1000, delay=3):
    print(message)
    await asyncio.sleep(delay)
    return result


async def main():
    start = time.perf_counter()

    task_1 = asyncio.create_task(
        call_api('Get stock price of GOOG...', 300)
    )

    task_2 = asyncio.create_task(
        call_api('Get stock price of APPL...', 300)
    )

    price = await task_1
    print(price)

    price = await task_2
    print(price)

    end = time.perf_counter()
    print(f'It took {round(end-start,0)} second(s) to complete.')


asyncio.run(main())Linguagem de código:  Python  ( python )

Saída:

Get stock price of GOOG...
Get stock price of APPL...
300
300
It took 3.0 second(s) to complete.Linguagem de código:  Python  ( python )

Como funciona.

Primeiro, inicie um cronômetro:

start = time.perf_counter()Linguagem de código:  Python  ( python )

Em seguida, crie uma tarefa e agende-a para ser executada imediatamente no loop de eventos:

task_1 = asyncio.create_task(
   call_api('Get stock price of GOOG...', 300)
)Linguagem de código:  Python  ( python )

Em seguida, crie outra tarefa e agende-a para ser executada imediatamente no loop de eventos:

task_2 = asyncio.create_task(
    call_api('Get stock price of APPL...', 400)
)Linguagem de código:  Python  ( python )

Depois disso, aguarde a conclusão das tarefas:

price = await task_1
print(price)

price = await task_2
print(price)Linguagem de código:  Python  ( python )

É importante utilizar a awaitpalavra-chave para aguardar as tarefas em algum momento do programa.

Se não usássemos a awaitpalavra-chave, o Python agendaria a execução da tarefa, mas a interromperia quando asyncio.run()o loop de eventos fosse encerrado.

A imagem a seguir ilustra o fluxo de execução do programa:

Simultaneidade create_task do Python

Por fim, mostre o tempo que leva para completar a main()função:

end = time.perf_counter()
print(f'It took {round(end-start,0)} second(s) to complete.')Linguagem de código:  Python  ( python )

Ao usar a create_task()função, o programa fica muito mais rápido. Quanto mais tarefas você executa, mais rápido será.

Executando outras tarefas enquanto espera

Quando o call_apiestiver em execução, você poderá executar outras tarefas. Por exemplo, o programa a seguir exibe uma mensagem a cada segundo enquanto aguarda as call_apitarefas:

import asyncio
import time


async def call_api(message, result=1000, delay=3):
    print(message)
    await asyncio.sleep(delay)
    return result


async def show_message():
    for _ in range(3):
        await asyncio.sleep(1)
        print('API call is in progress...')


async def main():
    start = time.perf_counter()

    message_task = asyncio.create_task(
        show_message()
    )

    task_1 = asyncio.create_task(
        call_api('Get stock price of GOOG...', 300)
    )

    task_2 = asyncio.create_task(
        call_api('Get stock price of APPL...', 300)
    )

    price = await task_1
    print(price)

    price = await task_2
    print(price)

    await message_task

    end = time.perf_counter()
    print(f'It took {round(end-start,0)} second(s) to complete.')


asyncio.run(main())Linguagem de código:  Python  ( python )

Saída:

Get stock price of GOOG...
Get stock price of APPL...
API call is in progress...
API call is in progress...
API call is in progress...
300
300Linguagem de código:  Python  ( python )

A imagem a seguir ilustra o fluxo de execução:

Resumo

  • Uma tarefa é um wrapper de uma corrotina que agenda a corrotina para ser executada no loop de eventos o mais rápido possível.
  • Use a create_task()função da asynciobiblioteca para criar uma tarefa.
  • Use a awaitpalavra-chave com a tarefa em algum ponto do programa para que a tarefa possa ser concluída antes que o loop de eventos seja fechado pela asyncio.run()função.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *