[quote=lkbm][quote=javaflex]
Para não ter threads bloqueantes ocupando o servidor web. Senão dependendo do uso simultâneo e limite do servidor web a aplicação pode parar de responder.[/quote]
Na maioria da vezes (98%?), o gargalo de uma aplicação web é o banco, e não no modelo de threads usado pelo servidor.
Então repito a pergunta: tirando aficcionados node.js, quem mais liga para threads não-bloqueantes no backend?[/quote]
Você mesmo meio que encaminhou a resposta, como exemplo o banco de dados. Supondo então ter um processo pesado e que ao mesmo tempo o resultado de um usuário nao dependa do outro, esse pode ser um caso para não deixar este processo na thread do request, se houver possibilidade de atingir limite de requests ocupados simultâneos no web server. Os recursos estão ai para serem usados de acordo com o cenário, se o problema não existe não usa.
[quote=javaflex]
Você mesmo meio que encaminhou a resposta, como exemplo o banco de dados. Supondo então ter um processo pesado e que ao mesmo tempo o resultado de um usuário nao dependa do outro, esse pode ser um caso para não deixar este processo na thread do request, se houver possibilidade de atingir limite de requests ocupados simultâneos no web server. Os recursos estão ai para serem usados de acordo com o cenário, se o problema não existe não usa.[/quote]
Mas a solução para o cenário que você descreve não é usar operações assíncronas para processamento pesado. Até porque não importa se você usa a thread do request, ou uma thread criada no request handler da sua aplicação, em ambos os casos estará usando recursos computacionais do servidor pra fazer o processamento, e deixando de usar os mesmos recursos para tratar requisições do cliente.
A solução para esse caso é migrar o processamento pesado para outra máquina.
[quote=lkbm][quote=javaflex]
Você mesmo meio que encaminhou a resposta, como exemplo o banco de dados. Supondo então ter um processo pesado e que ao mesmo tempo o resultado de um usuário nao dependa do outro, esse pode ser um caso para não deixar este processo na thread do request, se houver possibilidade de atingir limite de requests ocupados simultâneos no web server. Os recursos estão ai para serem usados de acordo com o cenário, se o problema não existe não usa.[/quote]
Mas a solução para o cenário que você descreve não é usar operações assíncronas para processamento pesado. Até porque não importa se você usa a thread do request, ou uma thread criada no request handler da sua aplicação, em ambos os casos estará usando recursos computacionais do servidor pra fazer o processamento, e deixando de usar os mesmos recursos para tratar requisições do cliente.
A solução para esse caso é migrar o processamento pesado para outra máquina.[/quote]
Não me refiro a desempenho ou onde o processo pesado vai rodar, mas sobre o limite de requests ocupadas no servidor web, onde seja la onde for rodar o processo pesado, a thread do request não vai ficar travada.
[quote=javaflex]
Não me refiro a desempenho ou onde o processo pesado vai rodar, mas sobre o limite de requests ocupadas no servidor web, onde seja la onde for rodar o processo pesado, a thread do request não vai ficar travada.[/quote]
Se o cliente precisa saber o resultado da operação, ele vai ter que esperar na thread ou vai ter que fazer outra requisição para obter a resposta. Isso aumenta, não diminui o número de requests ao servidor.
De qualquer maneira, a decisão de travar é do programador da aplicação e depende do custo da operação a ser realizada (que é conhecido pelo programador no momento da codificação). Ao meu ver, não faz muito sentido o desenvolvedor basear essa decisão no número de requests que o servidor web em produção vai estar configurado para suportar, porque geralmente ele não tem essa informação enquanto esta desenvolvendo a aplicação.
A questão está na otimização do uso dos recursos. Tornar o ambiente síncrono consome muitos recursos: é necessário garantir trocas de mensagens de acks, é necessário tratar contextos de threads, etc.
Programar de maneira assíncrona libera o processador para tratar de outras atividades a um custo bem menor.
Além disso, quando a aplicação como um todo está escrita considerando assincronia, fica bem mais fácil paralelizar tarefas.
[quote=ViniGodoy]A questão está na otimização do uso dos recursos. Tornar o ambiente síncrono consome muitos recursos: é necessário garantir trocas de mensagens de acks, é necessário tratar contextos de threads, etc.
Programar de maneira assíncrona libera o processador para tratar de outras atividades a um custo bem menor.
Além disso, quando a aplicação como um todo está escrita considerando assincronia, fica bem mais fácil paralelizar tarefas.[/quote]
Quando um método é chamado em qualquer linguagem você esta fazendo uma chamada síncrona. Então por padrão, o ambiente é síncrono.
Pra realizar chamadas de maneira assíncrona, deve existir alguma vantagem. No caso de aplicações frontend essa vantagem está em não bloquear a thread responsável por atualizar a interface do usuário, garantindo assim uma interface sempre responsiva.
Qual a vantagem de async em aplicações de backend?
Mesmo em aplicações frontend, async só é usado quando o desenvolvedor da aplicação identifica uma operação que pode bloquear a interface do usuário. Portanto não é correta a afirmação que a aplicação é toda escrita considerando assíncrona.
Quando um método é chamado sim, mas considere o exemplo que foi dado, do banco de dados. Para que você tenha a ilusão de sincronismo num “executeQuery” há um controle do lado cliente, para fazer a thread que deu o select dormir, esperar mensagem de confirmação, gerenciar timeouts, etc. E há um controle do lado do banco, para enviar essas mensagens.
Isso torna mais complexa a implementação do banco e dos drivers. Boa parte disso isso pode ser evitada se os dois lados estiverem preparados para chamadas assíncronas.
Esse tipo de arquitetura facilita drasticamente a comunicação entre diferentes threads, ou entre aplicações em diferentes máquinas.
[quote=ViniGodoy]Quando um método é chamado sim, mas considere o exemplo que foi dado, do banco de dados. Para que você tenha a ilusão de sincronismo num “executeQuery” há um controle do lado cliente, para fazer a thread que deu o select dormir, esperar mensagem de confirmação, gerenciar timeouts, etc. E há um controle do lado do banco, para enviar essas mensagens.
Isso torna mais complexa a implementação do banco e dos drivers. Boa parte disso isso pode ser evitada se os dois lados estiverem preparados para chamadas assíncronas.
Esse tipo de arquitetura facilita drasticamente a comunicação entre diferentes threads, ou entre aplicações em diferentes máquinas.[/quote]
Se facilita a implementação do banco e dos drivers não sei, mas de que maneira facilitaria a comunicação?
Se o cliente precisa dos dados ele só precisa esperar pela resposta do banco, o que tem de complicado nisso?
[quote=lkbm]Se facilita a implementação do banco e dos drivers não sei, mas de que maneira facilitaria a comunicação?
Se o cliente precisa dos dados ele só precisa esperar pela resposta do banco, o que tem de complicado nisso?
Qual seria a alternativa mais simples neste caso?[/quote]
É um pouco compicado explicar aqui como isso funciona por baixo dos panos. É, inclusive, o tema de dois meses da minha aula de redes.
A complexidade está no fato de que as duas máquinas não estão, efetivamente, operando ao mesmo tempo. Então, há a necessidade de avisar que o comando foi recebido (ACK), que a outra máquina ainda está viva e processando (KEEP_ALIVE), e que o processamento acabou. Tudo isso para criar a ilusão de sincronia.
A razão por trás da sincronia é que, depois de pronta, fica muito mais fácil programar. É conceitualmente simples fazer um simples "executeQuery"e entender isso como uma chamada de função. Porém, essa ilusão de simplicidade vem com um custo.
Eu nunca vi nenhum trabalho sério que quantifica se esse custo é tão alto ao ponto disso, por si só, justificar toda a mudança de paradigma que o node propõe.
A razão pelo qual gosto do async é justamente o fato de tornar fácil criar threads assíncronas para calculos ou processamento batch e depois sincroniza-las em algum ponto. Do lado do servidor, a vantagem está justamente no fato de você poder disparar vários pequenos processamentos desses, e depois poder espera-los em ordem, ou coloca-los em condição de corrida. Quando há também formas de você declarar quais processamentos estão em contextos distintos (como se faz no C#) e quais dados são trocados em sua fronteira, fica muito fácil criar um escalonador que possa decidir sozinho se um determinado trecho de código pode ser disparado na mesma thread, numa thread separada, ou numa máquina remota, ou mesmo com redundância em várias máquinas (como o Azure faz). Assim é possível ter backends muito poderosos sem você ter um esforço muito grande de gerenciar threads e paralelismo na mão.
[quote=lkbm]JavaScript é diferente porque qualquer coisa pode bloquear a interface, já que só existe uma thread e ela é usada pra tudo.
Estava me referindo a linguagens de verdade.[/quote]
Por favor, leia o material que passei e entenda o que estou falando. No caso, o trecho em questão está sincronizando threads que são automaticamente disparadas pelo browser para download de arquivos, e cujo resultado tem que ser exibido em ordem.
Uma situação facilmente necessária e que pode ser reproduzida no backend, em linguagens de verdade, para threads que o próprio programador queira criar para processamentos diversos.
Agora entendi porque isso é uma vantagem. Porque você usa uma linguagem que só tem uma thread no servidor. Portanto, no modelo javascript de programação esse tipo de coisa é incentivado.
Mas linguagens que não compartilham das mesmas limitações que javascript, não vejo vantagem disparar processos dessa maneira.
Eram dois assuntos diferentes. O primeiro, a resposta da pergunta de “porque projetar tudo para ser assíncrono permite que o servidor seja mais leve e tenha mais performance”. A segunda é “para o programador de backend, qual é a vantagem de ter mecanismos assíncronos?”.
Isso é válido para qualquer linguagem. Você irá disparar processos dessa maneira em qualquer linguagem. Java, C# ou JavaScript. E vai querer espera-los. Não é à toa que já existem APIs para isso no Java - como boa parte do pacote java.util.synchronized.
[quote=ViniGodoy]
Isso é válido para qualquer linguagem. Você irá disparar processos dessa maneira em qualquer linguagem. Java, C# ou JavaScript. E vai querer espera-los. Não é à toa que já existem APIs para isso no Java - como boa parte do pacote java.util.synchronized.[/quote]
Não acha que existe uma diferença entre ter uma API que o desenvolvedor pode optar usar, e o que acontece com javascript onde você é praticamente obrigado a seguir esse modelo de programação se quiser ter a oportunidade de fazer alguma coisa com a linguagem?
[quote=lkbm][quote=javaflex]
Não me refiro a desempenho ou onde o processo pesado vai rodar, mas sobre o limite de requests ocupadas no servidor web, onde seja la onde for rodar o processo pesado, a thread do request não vai ficar travada.[/quote]
Se o cliente precisa saber o resultado da operação, ele vai ter que esperar na thread ou vai ter que fazer outra requisição para obter a resposta. Isso aumenta, não diminui o número de requests ao servidor.
De qualquer maneira, a decisão de travar é do programador da aplicação e depende do custo da operação a ser realizada (que é conhecido pelo programador no momento da codificação). Ao meu ver, não faz muito sentido o desenvolvedor basear essa decisão no número de requests que o servidor web em produção vai estar configurado para suportar, porque geralmente ele não tem essa informação enquanto esta desenvolvendo a aplicação.[/quote]
Tambem nao me refiro ao cliente, ele vai esperar sim, mas a thread do request gerenciada pelo webserver nao vai estar travada pela efetiva execucao do processo pesado. Existem sim casos de limitação, normalmente o erro retornado quando estoura no IIS é “Server too busy”, clássico ocorrer em hospedagens compartilhadas. No Java estou por fora, não tenho certeza mas parece que no Tomcat por exemplo tem algo relacionado a “maxThreads”.