Python assíncio.gather()

Resumo : neste tutorial, você aprenderá como usar a asyncio.gather()função Python para executar várias operações assíncronas.

Introdução à função Python asyncio.gather()

Às vezes, você pode querer executar várias operações assíncronas e obter os resultados assim que forem concluídos. Para fazer isso você pode usar a asyncio.gather()função:

gather(*aws, return_exceptions=False) -> Future[tuple[()]]Linguagem de código:  Python  ( python )

A asyncio.gather()função possui dois parâmetros:

  • awsé uma sequência de objetos aguardáveis. Se algum objeto for awsuma corrotina , a asyncio.gather()função irá agendá-lo automaticamente como uma tarefa .
  • return_exceptionsé Falsepor padrão. Se ocorrer uma exceção em um objeto aguardável, ela será imediatamente propagada para a tarefa que aguarda asyncio.gather(). Outros aguardáveis ​​continuarão em execução e não serão cancelados .

O asyncio.gather()retorna os resultados dos aguardáveis ​​como uma tupla com a mesma ordem em que você passa os aguardáveis ​​para a função.

Se return_exceptionsfor True. O asyncio.gather()irá adicionar a exceção , se houver, ao resultado e não propagará a exceção para o chamador.

Exemplos de asyncio.gather() em Python

Vejamos alguns exemplos de uso da asyncio.gather()função.

1) Usando asyncio.gather() para executar múltiplas operações assíncronas

O exemplo a seguir usa asyncio.gather()para executar duas operações assíncronas e exibe os resultados:

import asyncio


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


async def main():
    a, b = await asyncio.gather(
        call_api('Calling API 1 ...', 1),
        call_api('Calling API 2 ...', 2)
    )
    print(a, b)


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

Saída:

Calling API 1 ...
Calling API 2 ...
100 200Linguagem de código:  Python  ( python )

Como funciona.

Primeiro, defina uma corrotina call_api()que simule uma operação assíncrona. O call_api()exibe uma mensagem, atrasa alguns segundos e retorna um resultado:

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

Segundo, use a asyncio.gather()função para executar dois call_api():

async def main():
    a, b = await asyncio.gather(
        call_api('Calling API 1 ...', 100, 1),
        call_api('Calling API 2 ...', 200, 2)
    )
    print(a, b)Linguagem de código:  Python  ( python )

A primeira corrotina leva 1 segundo e retorna 100, enquanto a segunda corrotina leva 2 segundos e retorna 100.

Após 2 segundos, a coleta retorna o resultado como uma tupla que contém o resultado da primeira e da segunda corrotinas.

Observe que a é 100 e b é 200, que são os resultados da corrotina correspondente que passamos para a asyncio.gather()função.

2) Usando asyncio.gather() para executar múltiplas operações assíncronas com exceções

O exemplo a seguir mostra como usar a asyncio.gather()função para executar diversas operações assíncronas em que uma operação gera uma exceção:

import asyncio


class APIError(Exception):
    def __init__(self, message):
        self._message = message

    def __str__(self):
        return self._message


async def call_api_failed():
    await asyncio.sleep(3)
    raise APIError('API failed')


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


async def main():
    a, b, c = await asyncio.gather(
        call_api('Calling API 1 ...', 100, 1),
        call_api('Calling API 2 ...', 200, 2),
        call_api_failed()
    )
    print(a, b, c)


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

Como funciona.

Primeiro, defina uma nova APIErrorclasse de exceção que herda da Exceptionclasse:

class APIError(Exception):
    def __init__(self, message):
        self._message = message

    def __str__(self):
        return self._messageLinguagem de código:  Python  ( python )

Segundo, defina a call_api_failed()corrotina que atrasa 1 segundo e gera uma APIErrorexceção:

async def call_api_failed():
    await asyncio.sleep(3)
    raise APIError('API failed')Linguagem de código:  Python  ( python )

Terceiro, passe três corrotinas para a asyncio.gather()função. Após um segundo, call_api_failed()gera uma exceção que se propaga imediatamente para a asyncio.gather()função:

async def main():
    a, b, c = await asyncio.gather(
        call_api('Calling API 1 ...', 100, 1),
        call_api('Calling API 2 ...', 200, 2),
        call_api_failed()
    )
    print(a, b, c)Linguagem de código:  Python  ( python )

Se você executar o programa, verá a APIErrorexceção.

3) Usando asyncio.gather() para retornar uma exceção no resultado

Para obter a exceção no resultado, você define o return_exceptionsparâmetro Trueda seguinte forma:

import asyncio


class APIError(Exception):
    def __init__(self, message):
        self._message = message

    def __str__(self):
        return self._message


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


async def call_api_failed():
    await asyncio.sleep(1)
    raise APIError('API failed')


async def main():
    a, b, c = await asyncio.gather(
        call_api('Calling API 1 ...', 100, 1),
        call_api('Calling API 2 ...', 200, 2),
        call_api_failed(),
        return_exceptions=True
    )
    print(a, b, c)


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

Saída:

Calling API 1 ...
Calling API 2 ...
100 200 API failedLinguagem de código:  Python  ( python )

Neste exemplo, como the return_exceptionsestá definido como True, the asyncio.gather()retorna a exceção como parte do resultado.

Resumo

  • O asyncio.gather()executa várias operações assíncronas, agrupa uma corrotina como uma tarefa e retorna uma tupla de resultados na mesma ordem dos aguardáveis.
  • Defina return_exceptionscomo Truepara permitir que erros sejam retornados como resultados.

Deixe um comentário

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