Erlang, Go e Rust afirmam, de uma maneira ou de outra, que eles oferecem suporte à programação simultânea com "threads" / corotinas baratas. As Perguntas frequentes do Go afirmam:
É prático criar centenas de milhares de goroutines no mesmo espaço de endereço.
O Rust Tutorial diz:
Como as tarefas são significativamente mais baratas de criar do que os threads tradicionais, o Rust pode criar centenas de milhares de tarefas simultâneas em um sistema típico de 32 bits.
O tamanho do heap inicial padrão de 233 palavras é bastante conservador para oferecer suporte aos sistemas Erlang com centenas de milhares ou até milhões de processos.
Minha pergunta: que tipo de aplicativo requer tantos threads simultâneos de execução? Apenas os servidores da Web mais movimentados recebem até milhares de visitantes simultâneos. Os aplicativos do tipo chefe-trabalhador / despachante de emprego que escrevi atingiram retornos decrescentes quando o número de encadeamentos / processos é muito maior que o número de núcleos físicos. Suponho que possa fazer sentido para aplicativos numéricos, mas, na realidade, a maioria das pessoas delega paralelismo a bibliotecas de terceiros escritas em Fortran / C / C ++, não nessas linguagens de nova geração.
fonte
Respostas:
um caso de uso - websockets:
como os websockets têm vida longa em comparação com solicitações simples, em um servidor ocupado, muitos websockets se acumulam com o tempo. os microtreads oferecem uma boa modelagem conceitual e também uma implementação relativamente fácil.
Em geral, os casos em que várias unidades mais ou menos autônomas aguardam a ocorrência de determinados eventos devem ser bons casos de uso.
fonte
Talvez ajude pensar no que Erlang foi originalmente projetado para fazer, que era gerenciar telecomunicações. Atividades como roteamento, comutação, coleta / agregação de sensores, etc.
Trazendo isso para o mundo da web - considere um sistema como o Twitter . O sistema provavelmente não usaria microfones na geração de páginas da Web, mas poderia usá-los em sua coleção / armazenamento em cache / distribuição de tweets.
Este artigo pode ser de ajuda adicional.
fonte
Em um idioma em que você não tem permissão para modificar variáveis, o simples ato de manter o estado requer um contexto de execução separado (que a maioria das pessoas chamaria de um encadeamento e Erlang chama um processo). Basicamente, tudo é um trabalhador.
Considere esta função Erlang, que mantém um contador:
Em uma linguagem OO convencional como C ++ ou Java, você faria isso tendo uma classe com um membro da classe privada, métodos públicos para obter ou alterar seu estado e um objeto instanciado para cada contador. Erlang substitui a noção do objeto instanciado por um processo, a noção de métodos por mensagens e manutenção de estado com chamadas finais que reiniciam a função com quaisquer valores que compõem o novo estado. O benefício oculto desse modelo - e a maior parte da razão de ser de Erlang - é que o idioma serializa automaticamente o acesso ao valor do contador através do uso de uma fila de mensagens, tornando o código simultâneo muito fácil de implementar com um alto grau de segurança .
Você provavelmente está acostumado à ideia de que as alternâncias de contexto são caras, o que ainda é verdade da perspectiva do sistema operacional host. O tempo de execução Erlang é, por si só, um pequeno sistema operacional ajustado para que a alternância entre seus próprios processos seja rápida e eficiente, mantendo o número de alternâncias de contexto que o SO faz no mínimo. Por esse motivo, ter muitos milhares de processos não é um problema e é incentivado.
fonte
counter/1
deve usar um minúsculo c;) Tentei corrigi-lo, mas o StackExchange não gosta de edições de 1 caractere.1) O fato de uma linguagem "escalar" significa que há menos chances de você abandonar essa linguagem quando as coisas ficarem mais complexas no futuro. (Isso é chamado de conceito "Produto Inteiro".) Muitas pessoas estão abandonando o Apache for Nginx por esse mesmo motivo. Se você estiver perto do "limite máximo" imposto pelo overhead de threads, ficará assustado e começará a pensar em maneiras de superar isso. Os sites nunca podem prever quanto tráfego obterão, portanto, gastar um pouco de tempo tornando as coisas escaláveis é razoável.
2) Uma goroutine por solicitação apenas no início. Existem muitas razões para usar goroutines internamente.
O desempenho não é o único motivo para dividir um programa no CSP . Na verdade, ele pode facilitar a compreensão do programa e alguns problemas podem ser resolvidos com muito menos código.
Como nos slides vinculados acima, ter simultaneidade no seu código é uma maneira de organizar o problema. Não ter goroutines é como não ter uma estrutura de dados Map / Dictonary / Hash no seu idioma. Você pode sobreviver sem ele. Mas uma vez que você o possui, você começa a usá-lo em qualquer lugar, e isso realmente simplifica seu programa.
No passado, isso significava "rolar o seu próprio" programação multithread. Mas isso era complexo e perigoso - ainda não existem muitas ferramentas para garantir que você não esteja criando corridas. E como você evita que um futuro mantenedor cometa um erro? Se você observar programas grandes / complexos, verá que eles gastam MUITOS recursos nessa direção.
Como a concorrência não é uma parte de primeira classe da maioria dos idiomas, os programadores de hoje têm um ponto cego para saber por que isso seria útil para eles. Isso só se tornará mais aparente à medida que todo telefone e relógio de pulso se aproxima de 1000 núcleos. Navegue com uma ferramenta incorporada de detector de corrida.
fonte
Para Erlang, é comum ter um processo por conexão ou outra tarefa. Por exemplo, um servidor de streaming de áudio pode ter 1 processo por usuário conectado.
A Erlang VM é otimizada para lidar com milhares ou mesmo centenas de milhares de processos, tornando as alternâncias de contexto muito baratas.
fonte
Conveniência. Quando eu comecei a programar multi-threads, eu fazia muita simulação e desenvolvimento de jogos por diversão. Eu achei que era de grande conveniência apenas girar um thread para cada objeto e deixá-lo fazer suas próprias coisas, em vez de processar cada um por um loop. Se o seu código não for perturbado por um comportamento não determinístico e você não tiver colisões, isso poderá facilitar a codificação. Com a energia disponível para nós agora, se eu voltar a isso, posso facilmente imaginar girando alguns milhares de threads devido à capacidade e memória de processamento suficientes para lidar com tantos objetos discretos!
fonte
Um exemplo simples para Erlang, projetado para comunicação: transferência de pacotes de rede. Ao fazer uma solicitação http, você pode ter milhares de pacotes TCP / IP. Acrescente a isso que todos se conectam ao mesmo tempo e você tem seu caso de uso.
Considere muitos aplicativos usados internamente por qualquer grande empresa para lidar com seus pedidos ou o que for necessário. Servidores da Web não são a única coisa que precisa de threads.
fonte
Algumas tarefas de renderização vêm à mente aqui. Se você estiver executando uma longa cadeia de operações em todos os pixels de uma imagem e se essas operações forem paralelizáveis, mesmo uma imagem relativamente pequena de 1024x768 estará no campo "centenas de milhares".
fonte