Como o Waitress lida com tarefas simultâneas?


8

Estou tentando criar um servidor web python usando Django e Waitress, mas gostaria de saber como o Waitress lida com solicitações simultâneas e quando o bloqueio pode ocorrer.


Embora a documentação do Waitress mencione que vários threads de trabalho estão disponíveis, ela não fornece muitas informações sobre como eles são implementados e como o GIL do python os afeta (ênfase minha):

Quando um canal determina que o cliente enviou pelo menos uma solicitação HTTP válida completa, ele agenda uma "tarefa" com um "despachante de encadeamentos". O distribuidor de encadeamentos mantém um conjunto fixo de encadeamentos de trabalho disponíveis para realizar o trabalho do cliente (por padrão, 4 encadeamentos). Se um segmento de trabalho estiver disponível quando uma tarefa for agendada, o segmento de trabalho executará a tarefa. A tarefa tem acesso ao canal e pode gravar de volta no buffer de saída do canal. Quando todos os segmentos de trabalho estiverem em uso , as tarefas agendadas aguardarão na fila para que um segmento de trabalho fique disponível.

Também não parece haver muita informação sobre o Stackoverflow. Da pergunta "O trabalhador assíncrono de Gunicorn é análogo a Garçonete?" :

A garçonete possui um encadeamento assíncrono mestre que armazena em buffer as solicitações e enfileira cada solicitação a um de seus encadeamentos de trabalho de sincronização quando a E / S da solicitação é concluída.


Essas declarações não abordam o GIL (pelo menos no meu entendimento) e seria ótimo se alguém pudesse elaborar mais sobre como os threads de trabalho funcionam para a Waitress. Obrigado!


Você conseguiu uma solução para isso?
— variável

@ variável Infelizmente não. Ao olhar brevemente para o repositório de garçons do github , parece que eles não fizeram nada para contornar o GIL, embora eu não possa dizer com certeza. No momento, minha equipe continua com o Waitress, pois nosso aplicativo não exige um nível de simultaneidade muito alto.
— MoltenMuffins 6/03

Ao usar o servidor padrão do balão de desenvolvimento, podemos definir o número de processos usando werkzeug.palletsprojects.com/en/1.0.x/serving/… - isso não existe na garçonete?
— variável

Sim, o número de trabalhadores pode ser configurado, mas isso não diz nada sobre seu comportamento de bloqueio
— MoltenMuffins

Se um trabalhador significa um processo independente, isso significa que cada processo tem seu próprio interpretador python. não é?
— variável

Respostas:


1

Veja como os servidores assíncronos controlados por eventos geralmente funcionam:

  • Inicie um processo e ouça as solicitações recebidas. A utilização da API de notificação de eventos do sistema operacional facilita muito o atendimento a milhares de clientes a partir de um único encadeamento / processo.
  • Como existe apenas um processo gerenciando todas as conexões, você não deseja executar nenhuma tarefa lenta (ou bloqueadora) nesse processo. Porque então ele irá bloquear o programa para cada cliente.
  • Para executar tarefas de bloqueio, o servidor delega as tarefas para "trabalhadores". Os trabalhadores podem ser threads (executando no mesmo processo) ou processos separados (ou subprocessos). Agora, o processo principal pode continuar atendendo os clientes enquanto os trabalhadores executam as tarefas de bloqueio.

Como o Waitress lida com tarefas simultâneas?

Praticamente da mesma maneira que acabei de descrever acima. E para os trabalhadores, ele cria threads, não processos.

como o python GIL os afeta

Garçonete usa threads para trabalhadores. Então, sim, eles são afetados pelo GIL, pois não são realmente concorrentes, embora pareçam ser. "Assíncrono" é o termo correto.

Os threads no Python são executados em um único processo, em um único núcleo da CPU e não são executados em paralelo. Um encadeamento adquire o GIL por um período muito pequeno e executa seu código e, em seguida, o GIL é adquirido por outro encadeamento.

Mas como o GIL é lançado na E / S de rede, o processo pai sempre o adquirirá sempre que houver um evento de rede (como uma solicitação de entrada) e, dessa forma, você pode ter certeza de que o GIL não afetará as operações ligadas à rede ( como receber solicitações ou enviar respostas).

Por outro lado, os processos Python são realmente concorrentes: eles podem ser executados em paralelo em vários núcleos. Mas a garçonete não usa processos.

Você deveria estar preocupado?

Se você está apenas executando pequenas tarefas de bloqueio, como leitura / gravação em banco de dados e atendendo apenas algumas centenas de usuários por segundo, o uso de threads não é tão ruim assim.

Para atender a um grande volume de usuários ou executar tarefas de bloqueio de longa execução, você pode usar filas de tarefas externas como o Aipo . Isso será muito melhor do que gerar e gerenciar processos você mesmo.


É melhor usar um servidor de aplicativos baseado em processo para processar mais solicitações?
— variável

@ variável Se você estiver executando tarefas vinculadas à CPU (também conhecidas como tarefas de bloqueio) como cálculos pesados, sim, é melhor usar trabalhadores do processo. Mas existem projetos como o Aipo que ajudam a executar tarefas de bloqueio em "filas de tarefas" separadas. Portanto, não importa que tipo de servidor de aplicativos você esteja usando. Mas apenas para executar tarefas ligadas à rede (como aguardar solicitações de clientes ou buscar dados de API de terceiros), você não precisa de trabalhadores.
— xyres 13/03

@variable E se por servidor "baseado em processo" você quis dizer um servidor que cria um novo processo para cada solicitação, então não, essa é a maneira menos escalável. A maneira mais eficiente (e comum) é o que descrevi na parte superior da resposta: atender a todas as solicitações de um único processo principal e delegar tarefas de bloqueio aos trabalhadores (threads ou subprocessos).
— xyres 13/03

Por "delegar tarefas de bloqueio a trabalhadores (threads ou subprocessos)" - você quer dizer aipo?
— variável

@ variável Você pode manter um conjunto de subprocessos em seu programa e passar a eles as tarefas de bloqueio. Para projetos menores, essa abordagem é boa. O aipo lhe dará a vantagem da fácil escalabilidade. Você pode executá-lo facilmente em um único servidor ou em um cluster de servidores, dependendo de suas necessidades. Para projetos menores, pode ser um exagero. Você pode mudar para o Aipo, se e quando precisar.
— xyres 13/03
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.