Estou cansado de ouvir as pessoas recomendarem que você use apenas um thread por processador, enquanto muitos programas usam até 100 por processo! tome por exemplo alguns programas comuns
vb.net ide uses about 25 thread when not debugging
System uses about 100
chrome uses about 19
Avira uses more than about 50
Sempre que postar uma pergunta relacionada ao encadeamento, sou lembrado quase sempre que não devo usar mais de um encadeamento por processador e todos os programas mencionados acima estão arruinando o sistema com um único processador.
Respostas:
Possivelmente em HPC, onde você deseja a máxima eficiência - mas, do contrário, a coisa mais estúpida que ouvi hoje!
Você deve usar o número de threads que são apropriados para o design do programa e ainda fornecer desempenho aceitável.
Para um servidor Web, pode ser razoável disparar um encadeamento para cada conexão de entrada (embora haja maneiras melhores para servidores com muita carga).
Para um ide, cada ferramenta executada em seu próprio segmento não é irracional. Suspeito que muitos dos threads relatados para o .Net IDE sejam coisas como log e tarefas de E / S iniciadas em seus próprios threads, para que possam continuar desbloqueados.
fonte
O conselho de um thread por núcleo se aplica quando o objetivo é acelerar a execução paralela.
Um motivo completamente diferente e igualmente válido é a simplicidade do código quando ele precisa responder a eventos imprevisíveis. Portanto, se um programa precisar escutar em 100 soquetes e parecer dar toda a atenção a cada um, esse é o uso perfeito para o encadeamento. Outro exemplo é uma interface do usuário, na qual um thread lida com eventos da interface do usuário, enquanto outro realiza o processamento em segundo plano.
fonte
Você deseja um encadeamento para cada cálculo que possa prosseguir em taxas diferentes das de outros cálculos.
Para computação paralela ligada à CPU, que vem em grandes blocos de trabalho, geralmente você deseja um encadeamento por CPU, porque, quando todos estiverem ocupados, mais encadeamentos não ajudarão e apenas criarão sobrecarga no agendador. Se os blocos de trabalho tiverem tamanhos irregulares no tempo ou forem gerados dinamicamente em tempo de execução (geralmente acontece quando você tiver grandes estruturas de dados complexas para processar), convém anexar esses blocos a vários encadeamentos, para que um planejador sempre tenha um grande número de threads. defina para escolher quando algum bloco de trabalho for concluído, para manter todas as CPUs ocupadas.
Para o cálculo de ligação de E / S, geralmente você deseja um encadeamento para cada "canal" de E / S independente, pois eles se comunicam em taxas diferentes e os encadeamentos bloqueados no canal não impedem que outros encadeamentos progridam.
fonte
A regra geral para threads é que você deseja pelo menos um thread de trabalho "ativo" (capaz de executar seus comandos imediatamente após o tempo da CPU) para cada "unidade de execução" disponível no computador. Uma "unidade de execução" é um processador de instruções lógicas, portanto, um servidor Xeon com quatro núcleos e quatro núcleos com hyperthread teria 32 EUs (4 chips, 4 núcleos por chip, cada hyperthread). Seu Core i7 médio teria 8.
Um encadeamento por UE é o uso máximo da energia da CPU, desde que os encadeamentos estejam sempre em estado de execução; quase nunca é esse o caso, pois os threads precisam acessar a memória não armazenada em cache, o disco rígido, as portas de rede etc. que eles devem esperar e que não exigem atenção ativa da CPU para serem executados. Dessa forma, você pode aumentar ainda mais a eficiência geral com mais threads na fila e ansiosos para começar. Isso tem um custo; quando uma CPU alterna um encadeamento, deve armazenar em cache os registros, o ponteiro de execução e outras informações de estado normalmente mantidas no funcionamento mais interno de uma UE e acessadas muito rapidamente, permitindo que outras UEs nesse chip da CPU possam buscá-lo. Também requer threads no sistema operacional para decidir para qual thread deve ser alternado. Por fim, quando uma UE alterna threads, perde os ganhos de desempenho do pipelining usado pela maioria das arquiteturas de processador; ele precisa liberar o pipeline antes de alternar os threads. Mas, como tudo isso ainda leva muito menos tempo, em média, do que simplesmente esperar o disco rígido ou até a RAM voltar com informações, vale a pena o custo.
No entanto, em geral, quando você ultrapassa o dobro do número de threads "ativos" que os EUs, o sistema operacional começa a gastar mais dos threads de agendamento de tempo dos EUs e os EUs passam mais tempo alternando entre eles do que realmente são gastos executando threads ativos de programas. Este é o ponto das deseconomias de escala; na verdade, levará mais tempo para que um algoritmo multithread seja executado se você adicionar um thread extra nesse momento.
Portanto, no geral, você deseja manter pelo menos o número de threads em seu programa que possui UEs no computador, mas deseja evitar ter mais que o dobro do número que não está esperando ou dormindo.
fonte
Você deve usar um thread para:
Cada processador que você precisa para se manter ocupado.
Cada E / S pode ser útil pendente simultaneamente e não é possível executar de maneira não-bloqueadora. (Por exemplo, lê de um disco local.)
Cada tarefa que requer um encadeamento dedicado, por exemplo, chamar uma biblioteca que não possui interface sem bloqueio ou onde as interfaces sem bloqueio não são apropriadas. Isso inclui tarefas como monitorar o relógio do sistema, disparar cronômetros e assim por diante.
Alguns extras para proteger contra bloqueios inesperados, como falhas de página.
Alguns extras para proteger contra o bloqueio esperado que não valem a pena otimizar, por exemplo, em códigos não críticos. (Por exemplo, se você raramente precisar fazer uma solicitação de DNS, provavelmente não vale a pena fazer solicitações de DNS de forma assíncrona. Basta criar alguns threads extras e facilitar sua vida.)
Se você seguir a regra "um thread por processador", todo o seu código será crítico para o desempenho. Qualquer código que bloqueie por algum motivo significa que seu processo não pode usar esse processador. Isso torna a programação muito mais difícil sem uma boa razão.
fonte
Você pode gerar processos e encadeamentos para permitir a utilização de um sistema multicore \ multiprocessador para um único programa; nesse caso, você não obtém nenhum benefício (pelo menos para o único programa) de ter mais encadeamentos \ processos do que núcleos.
Ou você pode ter rotinas que pesquisam um evento que normalmente bloqueia a execução adicional. Em vez disso, amarre a CPU com a pesquisa. Em vez disso, você pode criar um encadeamento que ficará no estado inativo até que o evento apropriado o ative. Esse método é muito usado em servidores da Web e filas de eventos da GUI. A maioria dos programas deseja ter algum tipo de armazenamento central de dados (mesmo que seja o código de execução do programa) que todos os threads possam acessar, então acho que é por isso que eles usam threading nos processos.
fonte
Os aplicativos que você menciona raramente executam todas essas dezenas de threads simultaneamente. A maioria deles apenas fica lá porque está em um pool de threads . O aplicativo envia várias tarefas para uma fila, que é eliminada por threads no pool de threads.
Por que a piscina é tão grande então? Porque, muitas vezes, os threads precisam aguardar outros recursos, como disco, rede, usuário, algum outro thread, etc. Enquanto um thread estiver aguardando, é apropriado executar outros threads para utilizar totalmente o processador. O dimensionamento adequado da piscina é complicado, no entanto. Poucos threads e você perderá o desempenho porque o processador não é totalmente utilizado enquanto espera por algo. Muitos threads e você perderá o desempenho devido à alternância entre eles.
fonte