Artigo
· Set. 2 5min de leitura

Interoperabilidade Em Python update: suporte para async

Faz bastante tempo desde a última vez que escrevi uma postagem de atualização do IoP.

image

Então, o que há de novo desde o lançamento da interface de linha de comando IoP?

Dois novos grandes recursos foram adicionados ao IoP:

  • Rebranding: o módulogrongier.pex foi renomeado para iop para refletir o novo nome do projeto.
  • suporte Async: IoP agora suporta funções assíncronas e co-rotinas.

Rebranding

O módulo grongier.pex foi renomeado para iop para refletir o novo nome do projeto.

O módulo grongier.pex ainda está disponível para compatibilidade retroativa, mas será removido no futuro.

suporte Async

O IoP suporta chamadas assíncronas há um bom tempo, mas não era possível usar funções e co-rotinas assíncronas diretamente nele.

Antes de pular dentro desse novo recurso, vou explicar como chamadas assíncronas funcionam no InterSystems IRIS e apresentar dois exemplos de como usar chamadas assíncronas IoP.

Chamadas async legado

Vamos ver como chamadas async legado funcionam:

from iop import BusinessProcess
from msg import MyMessage


class MyBP(BusinessProcess):

    def on_message(self, request):
        msg_one = MyMessage(message="Message1")
        msg_two = MyMessage(message="Message2")

        self.send_request_async("Python.MyBO", msg_one,completion_key="1")
        self.send_request_async("Python.MyBO", msg_two,completion_key="2")

    def on_response(self, request, response, call_request, call_response, completion_key):
        if completion_key == "1":
            self.response_one = call_response
        elif completion_key == "2":
            self.response_two = call_response

    def on_complete(self, request, response):
        self.log_info(f"Received response one: {self.response_one.message}")
        self.log_info(f"Received response two: {self.response_two.message}")

Basicamente elas funcionam da mesma maneira que chamadas async funcionam em IRIS. O método send_request_async envia uma requisição ao Business Operation e o método on_response é chamado quando a resposta é recebida.

Você pode distinguir as respostas pelo parâmetro completion_key

Enviar múltiplas requisições síncronas

Não é exatamente um novo recurso, mas vale a pena mencionar que você pode mandar múltiplas requisições síncronas em paralelo:

from iop import BusinessProcess
from msg import MyMessage


class MyMultiBP(BusinessProcess):

    def on_message(self, request):
        msg_one = MyMessage(message="Message1")
        msg_two = MyMessage(message="Message2")

        tuple_responses = self.send_multi_request_sync([("Python.MyMultiBO", msg_one),
                                                        ("Python.MyMultiBO", msg_two)])

        self.log_info("All requests have been processed")
        for target,request,response,status in tuple_responses:
            self.log_info(f"Received response: {response.message}")

Aqui estamos mandando duas requisições ao mesmo Business Operation em paralelo.

A resposta é uma tupla com o objetivo, requisição, resposta e status de cada chamada.

É bastante útil quando você precisa enviar múltiplas requisições e não se importa com a ordem das respostas.

Funções Async e co-rotinas

Agora vamos ver como usar funções assíncronas e co-rotinas no IoP:

import asyncio

from iop import BusinessProcess
from msg import MyMessage


class MyAsyncNGBP(BusinessProcess):

    def on_message(self, request):

        results = asyncio.run(self.await_response(request))

        for result in results:
            print(f"Received response: {result.message}")

    async def await_response(self, request):
        msg_one = MyMessage(message="Message1")
        msg_two = MyMessage(message="Message2")

        # use asyncio.gather to send multiple requests asynchronously
        # using the send_request_async_ng method
        tasks = [self.send_request_async_ng("Python.MyAsyncNGBO", msg_one),
                 self.send_request_async_ng("Python.MyAsyncNGBO", msg_two)]

        return await asyncio.gather(*tasks)

Neste exemplo, estamos enviando múltiplas requisições para o mesmo Business Operation em paralelo usando o método send_request_async_ng.

Se você leu esse post cuidadosamente até este ponto, por favor comente "Boomerang". Isso pode ser um detalhe para você, mas para mim significa muito. Obrigado!

O método await_response é uma co-rotina que envia múltiplas requisições e espera por todas as respostas.
Graças a funçãoasyncio.gather`, podemos esperar por todas as respostas serem recebidas em paralelo

Os benefícios das funções e co-rotinas assíncronas são:

  • Melhor performance: você pode enviar múltiplas requisições em paralelo.
  • Mais fácil de ler e manter: você pode usar a palavra chave await para esperar por respostas.
  • Maior flexibilidade: você pode usar o módulo asyncio para criar fluxos de trabalho complexos
  • Mais controle: você pode usar o módulo asyncio para lidar com exceções e timeouts.

Conclusão

Quais são as diferenças entre send_request_async, send_multi_request_sync e send_request_async_ng?

  • send_request_async: envia uma requisição ao Business Operation e espera a resposta se o método on_response for implementado e o parâmetro completion_key usado
    • benefício: você pode usar chamadas assíncronas da maneira que está acostumado.
    • desvantagem: pode ser difícil de manter se você precisa enviar múltiplas requisições em paralelo.
  • send_multi_request_sync: envia múltiplas requisições ao mesmo Business Operation em paralelo e espera por todas as respostas para serem recebidas.
    • benefício: fácil de usar.
    • desvantagem: você pode controlar a ordem das respostas (quero dizer se a lista de respostas não for ordenada)
  • send_request_async_ng: envia múltiplas requisições ao mesmo Business Operation em paralelo e espera por todas as respostas.
    • benefício: você pode controlar a ordem das respostas
    • desvantagem: você precisa usar funções e co-rotinas assíncronas.

Feliz multithreading!

Discussão (0)1
Entre ou crie uma conta para continuar