Pensamentos iniciais
Como você chegou à conclusão de que algumas partes do sistema se sairiam melhor em outro idioma? Você está tendo problemas de desempenho? Quão graves são esses problemas? Se puder ser mais rápido, é essencial que seja mais rápido?
Assincronia de thread único
Existem várias perguntas e outros recursos da Web que já lidam com as diferenças, prós e contras da assincronia de thread único versus simultaneidade de vários threads. É interessante ler sobre o desempenho do modelo assíncrono de thread único do Node.js. quando E / S é o principal gargalo, e há muitas solicitações sendo atendidas ao mesmo tempo.
Os modelos Twisted, Tornado e outros assíncronos fazem excelente uso de um thread único. Como grande parte da programação da Web possui muitas E / S (rede, banco de dados etc.), o tempo gasto na espera de chamadas remotas aumenta significativamente. É o tempo que poderia ser gasto fazendo outras coisas - como iniciar outras chamadas ao banco de dados, renderizar páginas e gerar dados. A utilização desse segmento único é extremamente alta.
Um dos maiores benefícios da assincronia de thread único é que ela usa muito menos memória. Na execução de vários threads, cada thread requer uma certa quantidade de memória reservada. À medida que o número de threads aumenta, aumenta a quantidade de memória necessária apenas para a existência dos threads. Como a memória é finita, significa que há limites no número de threads que podem ser criados a qualquer momento.
Exemplo
No caso de um servidor Web, finja que cada solicitação recebe seu próprio encadeamento. Digamos que seja necessário 1 MB de memória para cada encadeamento e o servidor da Web tenha 2 GB de RAM. Esse servidor da Web seria capaz de processar (aproximadamente) 2000 solicitações a qualquer momento, antes que não houvesse memória suficiente para processar mais.
Se sua carga for significativamente maior que isso, as solicitações demorarão muito (ao aguardar a conclusão de solicitações mais antigas) ou você precisará lançar mais servidores no cluster para expandir o número possível de solicitações simultâneas. .
Simultaneidade multithread
A simultaneidade de vários segmentos depende da execução de várias tarefas ao mesmo tempo. Isso significa que, se um encadeamento estiver bloqueado aguardando o retorno de uma chamada do banco de dados, outras solicitações poderão ser processadas ao mesmo tempo. A utilização do encadeamento é menor, mas o número de encadeamentos em execução é muito maior.
O código multiencadeado também é muito mais difícil de raciocinar. Há problemas com bloqueio, sincronização e outros problemas divertidos de simultaneidade. A assincronia de thread único não sofre os mesmos problemas.
Porém, o código multiencadeado tem muito mais desempenho para tarefas intensivas da CPU . Se não houver oportunidades para um encadeamento "render", como uma chamada de rede que normalmente bloqueia, um modelo de encadeamento único simplesmente não terá nenhuma simultaneidade.
Ambos podem coexistir
É claro que há sobreposição entre os dois; eles não são mutuamente exclusivos. Por exemplo, o código multithread pode ser escrito de maneira não-bloqueante, para melhor utilizar cada thread.
A linha inferior
Há muitas outras questões a serem consideradas, mas eu gosto de pensar sobre as duas dessa maneira:
- Se o seu programa estiver vinculado à E / S , a assincronia de thread único provavelmente funcionará muito bem.
- Se o seu programa estiver vinculado à CPU , um sistema multi-thread provavelmente será o melhor.
No seu caso particular, você precisa determinar que tipo de trabalho assíncrono está sendo concluído e com que frequência essas tarefas surgem.
- Eles ocorrem em cada solicitação? Nesse caso, a memória provavelmente se tornará um problema à medida que o número de solicitações aumentar.
- Essas tarefas estão ordenadas? Nesse caso, você precisará considerar a sincronização se usar vários threads.
- Essas tarefas são intensivas em CPU? Em caso afirmativo, um thread único é capaz de acompanhar a carga?
Não existe uma resposta simples. Você deve considerar quais são seus casos de uso e projetar de acordo. Às vezes, um modelo de thread único assíncrono é melhor. Outras vezes, é necessário usar vários threads para obter um processamento paralelo maciço.
outras considerações
Há outros problemas que você precisa considerar também, em vez de apenas o modelo de concorrência escolhido. Você conhece Erlang ou Clojure? Você acha que seria capaz de escrever um código multithread seguro em um desses idiomas para melhorar o desempenho do seu aplicativo? Vai demorar muito tempo para se atualizar em um desses idiomas, e o idioma que você aprenderá o beneficiará no futuro?
E as dificuldades associadas à comunicação entre esses dois sistemas? Será muito complexo manter dois sistemas separados em paralelo? Como o sistema Erlang receberá tarefas do Django? Como Erlang comunicará esses resultados de volta ao Django? O desempenho é significativo o suficiente para que a complexidade adicionada valha a pena?
Pensamentos finais
Eu sempre achei o Django rápido o suficiente e é usado por sites com tráfego intenso. Existem várias otimizações de desempenho que você pode fazer para aumentar o número de solicitações simultâneas e o tempo de resposta. É certo que eu não fiz nada com o Celery até agora; portanto, as otimizações de desempenho usuais provavelmente não resolverão nenhum problema que você possa ter com essas tarefas assíncronas.
Claro, sempre há a sugestão de jogar mais hardware no problema. O custo de provisionar um novo servidor é mais barato que o custo de desenvolvimento e manutenção de um subsistema totalmente novo?
Fiz muitas perguntas neste momento, mas essa era minha intenção. A resposta não será fácil sem análise e mais detalhes. Ser capaz de analisar os problemas se resume a conhecer as perguntas a serem feitas, no entanto ... então espero ter ajudado nessa frente.
Meu pressentimento diz que uma reescrita em outro idioma é desnecessária. A complexidade e o custo provavelmente serão grandes demais.
Editar
Resposta ao acompanhamento
Seu acompanhamento apresenta alguns casos de uso muito interessantes.
1. Django trabalhando fora de solicitações HTTP
Seu primeiro exemplo envolveu a leitura de tags NFC e a consulta ao banco de dados. Não acho que escrever essa parte em outro idioma seja útil para você, simplesmente porque a consulta ao banco de dados ou a um servidor LDAP ficará vinculada à E / S da rede (e potencialmente ao desempenho do banco de dados). Por outro lado, o número de solicitações simultâneas será vinculado pelo próprio servidor, pois cada comando de gerenciamento será executado como seu próprio processo. Haverá tempo de configuração e desmontagem que afeta o desempenho, pois você não está enviando mensagens para um processo já em execução. No entanto, você poderá enviar várias solicitações ao mesmo tempo, pois cada uma será um processo isolado.
Nesse caso, vejo duas avenidas que você pode investigar:
- Verifique se o seu banco de dados é capaz de lidar com várias consultas ao mesmo tempo com o pool de conexões. (O Oracle, por exemplo, exige que você configure o Django de acordo
'OPTIONS': {'threaded':True}
.) Pode haver opções de configuração semelhantes no nível do banco de dados ou no Django que você pode ajustar para o seu próprio banco de dados. Independentemente do idioma em que você escreve suas consultas ao banco de dados, será necessário aguardar o retorno desses dados antes de acender os LEDs. O desempenho do código de consulta pode fazer a diferença, e o Django ORM não é muito rápido ( mas , geralmente rápido o suficiente).
- Minimize o tempo de configuração / desmontagem. Tenha um processo em execução constante e envie mensagens para ele. (Corrija-me se eu estiver errado, mas é nisso que a sua pergunta original está realmente se concentrando.) Se este processo está escrito em Python / Django ou se outro idioma / estrutura está coberto acima. Não gosto da ideia de usar comandos de gerenciamento com tanta frequência. É possível ter um pequeno pedaço de código em execução constantemente, que envia as mensagens dos leitores NFC para a fila de mensagens, que o Celery lê e encaminha para o Django? A configuração e desmontagem de um pequeno programa, mesmo que seja escrita em Python (mas não no Django!), Deve ser melhor do que iniciar e parar um programa Django (com todos os seus subsistemas).
Não tenho certeza de qual servidor da Web você está usando para o Django. mod_wsgi
para Apache permite configurar o número de processos e encadeamentos dentro dos processos que os serviços solicitam. Certifique-se de ajustar a configuração relevante do seu servidor da web para otimizar o número de solicitações que podem ser reparadas.
2. “Passagem de mensagem” com sinais do Django
Seu segundo caso de uso também é bastante interessante; Não tenho certeza se tenho as respostas para isso. Se você estiver excluindo instâncias de modelo e desejar operá-las posteriormente, pode ser possível serializá-las JSON.dumps
e desserializar JSON.loads
. Será impossível recriar completamente o gráfico de objetos posteriormente (consultando modelos relacionados), pois os campos relacionados são carregados com preguiça no banco de dados e esse link não existe mais.
A outra opção seria marcar de alguma forma um objeto para exclusão e excluí-lo apenas no final do ciclo de solicitação / resposta (após todos os sinais terem sido atendidos). Pode exigir um sinal personalizado para implementar isso, em vez de confiar post_delete
.