Python Tornado - Retorno post Retornar imediatamente enquanto a função assíncrona continua trabalhando

StackOverflow https://stackoverflow.com/questions/3869421

  •  28-09-2019
  •  | 
  •  

Pergunta

Então, eu tenho um manipulador abaixo:

class PublishHandler(BaseHandler):

    def post(self):
        message = self.get_argument("message")
        some_function(message)
        self.write("success")

O problema que estou enfrentando é que Some_Function () leva algum tempo para executar e gostaria que a solicitação de postagem retorne imediatamente quando chamada e para que alguma_function () fosse executada em outro thread/processo, se possível.

Estou usando o Berkeley DB como banco de dados e o que estou tentando fazer é relativamente simples.

Eu tenho um banco de dados de usuários, cada um com um filtro. Se o filtro corresponder à mensagem, o servidor enviará a mensagem ao usuário. Atualmente, estou testando com milhares de usuários e, portanto, após cada publicação de uma mensagem por meio de uma solicitação de postagem, está iterando milhares de usuários para encontrar uma correspondência. Esta é a minha implementação ingênua de fazer as coisas e, portanto, minha pergunta. Como faço isso melhor?

Foi útil?

Solução

Você pode conseguir isso usando o seu IOLoop's add_callback Método como assim:

loop.add_callback(lambda: some_function(message))

Tornado executará o retorno de chamada no próximo Ioloop Pass, que poderia (Eu teria que cavar as entranhas de Tornado para saber com certeza ou testá -lo alternativamente) permitem que a solicitação seja concluída antes que esse código seja executado.

A desvantagem é que o código de longa duração que você escreveu ainda levará tempo para executar, e isso pode acabar bloqueando outra solicitação. Isso não é o ideal se você tiver muitas dessas solicitações entrando de uma só vez.

A solução mais infalível é executá -la em um encadeamento ou processo separado. o melhor O caminho com o Python é usar um processo, devido ao GIL (eu recomendo ler isso se você não estiver familiarizado com ele). No entanto, em uma máquina de processador único, a implementação rosqueada funcionará da mesma forma e pode ser mais simples de implementar.

Se você estiver seguindo a rota rosqueada, poderá criar um bom módulo "executor assíncrono" com um mutex, um fio e uma fila. Confira o multiprocessing Módulo se você deseja seguir o caminho de usar um processo separado.

Outras dicas

Eu tentei isso e acredito que a solicitação não é concluída antes que os retornos de chamada sejam chamados.

Eu acho que um hack sujo seria chamar dois níveis de add_callback, por exemplo:

  def get(self):
    ...
    def _defered():
      ioloop.add_callback(<whatever you want>)
    ioloop.add_callback(_defered)
    ...

Mas esses são hacks, na melhor das hipóteses. Estou procurando uma solução melhor no momento, provavelmente acabará com alguma fila de mensagens ou solução simples de threads.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top