Número ideal de threads por núcleo


280

Digamos que eu tenho uma CPU de 4 núcleos e quero executar algum processo no período mínimo de tempo. O processo é idealmente paralelelizável, para que eu possa executar partes dele em um número infinito de threads e cada thread leva a mesma quantidade de tempo.

Como tenho 4 núcleos, não espero aceleração executando mais threads do que núcleos, pois um único núcleo é capaz de executar um único thread em um determinado momento. Eu não sei muito sobre hardware, então isso é apenas um palpite.

Existe um benefício em executar um processo paralelamente agradável em mais threads do que núcleos? Em outras palavras, meu processo terminará mais rápido, mais lento ou na mesma quantidade de tempo se eu o executar usando 4000 threads em vez de 4 threads?

Respostas:


253

Se seus encadeamentos não executam E / S, sincronização etc., e não há mais nada em execução, um encadeamento por núcleo fornece o melhor desempenho. No entanto, isso provavelmente não é o caso. A adição de mais threads geralmente ajuda, mas após algum momento, eles causam alguma degradação no desempenho.

Há pouco tempo, eu estava testando o desempenho em uma máquina de dois núcleos quad-core executando um aplicativo ASP.NET no Mono sob uma carga bastante decente. Jogamos com o número mínimo e máximo de threads e, no final, descobrimos que, para aquele aplicativo específico nessa configuração específica, a melhor taxa de transferência estava entre 36 e 40 threads. Qualquer coisa fora desses limites teve um desempenho pior. Lição aprendida? Se eu fosse você, testaria com um número diferente de threads até encontrar o número certo para o seu aplicativo.

Uma coisa é certa: os threads de 4k levarão mais tempo. São muitas opções de contexto.


21
Eu acho que a resposta de Gonzalo é boa. Eu apenas acrescentaria que você deveria experimentar e medir. Seu programa será diferente do dele, do meu ou de qualquer outro e apenas as medidas do comportamento do seu próprio programa responderão às suas perguntas adequadamente. O desempenho de programas paralelos (ou concorrentes) não é uma área em que boas conclusões possam ser tiradas apenas dos primeiros princípios.
High Performance Mark

5
+1, + resposta: me surpreende que ter muito mais threads do que núcleos resulte em melhor desempenho, embora faça algum sentido se mais threads significarem maior parte do tempo compartilhada em comparação aos threads concorrentes. Seria bom que meu aplicativo pudesse detectar diferenças no desempenho e se ajustar automaticamente ao número ideal de threads.
Julieta

12
Não deveria surpreendê-lo em um cenário do mundo real. Os encadeamentos bloqueiam a espera de recursos de E / S, como acesso ao disco, rede, etc. E também aguardam que recursos que não sejam de E / S, como outros segmentos, terminem usando variáveis ​​compartilhadas. O que você realmente deseja alcançar é o número mínimo de encadeamentos, de modo que pelo menos um encadeamento por núcleo possa sempre estar em execução.
Patros

4
1 thread por núcleo não é o ideal. Ele precisa ser um pouco mais, de preferência o dobro disso, pois isso permitirá que outro encadeamento seja executado se um encadeamento estiver temporariamente bloqueado. Mesmo que apenas na memória. Isso é mais importnat se você tem sistemas (P4, i7, Sun Rocha etc) que recurso SMT / HT)
Marco van de Voort

1
Daí o "Isso provavelmente não é o caso" em minha resposta. Encontrar o número certo depende do aplicativo e da arquitetura em que ele é executado.
Gonzalo

129

Eu concordo com a resposta de @ Gonzalo. Eu tenho um processo que não executa E / S, e aqui está o que eu encontrei:

insira a descrição da imagem aqui

Observe que todos os encadeamentos funcionam em uma matriz, mas em intervalos diferentes (dois encadeamentos não acessam o mesmo índice); portanto, os resultados podem diferir se eles trabalharem em matrizes diferentes.

A máquina 1.86 é um macbook air com um SSD. O outro mac é um iMac com um disco rígido normal (acho que são 7200 rpm). A máquina Windows também possui um disco rígido de 7200 rpm.

Neste teste, o número ideal foi igual ao número de núcleos na máquina.


14
+1 para o gráfico. Claramente, 1 thread por núcleo é o melhor, mas é interessante que o sistema quad core pareça não ter números de threads mais altos (<100 de qualquer maneira) da maneira que os outros.
Jim Garrison

46
-1 para o gráfico! Curvas suaves através de coordenadas x com valor inteiro? Um salto selvagem de 1 2 3 para 10 20 30 para 50 100? E as coordenadas y que são múltiplos de 10 mais 2 para uma boa medida. Isso é tarefa do Excel, não é?
Spacedman

5
@ Spacedman Sim, é. As curvas suaves têm uma aparência muito mais agradável IMHO. : D
Motasim 27/12/12

22
@ PascalvKooten, O problema não é que parece bonito, é enganador à primeira vista. Primeiro, o eixo y começa em 42, exagerando a aparente diferença entre as máquinas testadas. Em segundo lugar, a estranha progressão dos valores do eixo x sugere que o 'tempo gasto' não escala linearmente com o 'número de threads', o que é especialmente verdadeiro para a linha azul. Eu acho que o problema que outras pessoas (inclusive eu) têm com isso é que ele deturpa os dados.
precisa saber é o seguinte

13
@ Spacedman A crítica no gráfico é a coisa mais ridícula que me deparei nas últimas 24 horas. O gráfico ajuda. Muito. Período. Poderia ter sido feito melhor? Ninguém se importa. Curva suave em vez de discreta? Esse é o seu problema ???? Presumo que todos vocês nunca incluam esse gráfico na resposta deles, porque não têm tempo / energia extra para fazê-lo parecer bom. Esse é o meu ponto.
Tyrex

49

Sei que essa pergunta é bastante antiga, mas as coisas evoluíram desde 2009.

Há duas coisas a serem consideradas agora: o número de núcleos e o número de threads que podem ser executados em cada núcleo.

Nos processadores Intel, o número de threads é definido pelo Hyperthreading, que é apenas 2 (quando disponível). Mas o Hyperthreading reduz o tempo de execução em dois, mesmo quando não estiver usando 2 threads! (ou seja, 1 pipeline compartilhado entre dois processos - isso é bom quando você tem mais processos, e não é tão bom assim. Mais núcleos são definitivamente melhores!)

Em outros processadores, você pode ter 2, 4 ou até 8 threads. Portanto, se você tiver 8 núcleos, cada um deles suportando 8 threads, poderá ter 64 processos em execução em paralelo sem alternância de contexto.

"Nenhuma troca de contexto" obviamente não é verdadeira se você executar com um sistema operacional padrão que fará a troca de contexto para todos os tipos de outras coisas fora de seu controle. Mas essa é a ideia principal. Alguns sistemas operacionais permitem alocar processadores para que apenas seu aplicativo tenha acesso / uso do referido processador!

Pela minha própria experiência, se você possui muitas E / S, vários threads são bons. Se você tiver um trabalho intensivo em memória muito pesada (fonte de leitura 1, fonte de leitura 2, computação rápida, gravação), ter mais threads não ajuda. Novamente, isso depende da quantidade de dados que você lê / grava simultaneamente (ou seja, se você usa o SSE 4.2 e lê valores de 256 bits, que interrompe todos os threads em sua etapa ... em outras palavras, 1 thread é provavelmente muito mais fácil de implementar e provavelmente mais rápido, se não realmente mais rápido.Isso dependerá da sua arquitetura de processo e memória, alguns servidores avançados gerenciam intervalos de memória separados para núcleos separados, para que threads separados sejam mais rápidos, pressupondo que seus dados sejam arquivados corretamente ... e é por isso que, em alguns arquiteturas, 4 processos serão executados mais rapidamente que 1 processo com 4 threads.)


4
Provavelmente existem outros, mas o que eu conheço é o processador POWER da IBM. Eles tinham sistemas com 4 ou 8 threads por processadores. Agora eles podem pôr em marcha em mais núcleos, para que eles oferecem 2 threads por núcleo, em vez ...
Alexis Wilke

Isso é antigo, mas a maioria dos processadores Intel i5, i7 tem CPUs com vários threads, como por exemplo, as CPUs i7 geralmente têm 4 núcleos, mas 8 threads.
Edgar.A

4
Os processadores não têm threads. Eles têm núcleos físicos e lógicos. Com o hyperthreading, um único núcleo físico funciona como dois núcleos lógicos. Eu tinha uma tecnologia que insistia que os processadores com threads eram uma coisa real, então desenhei uma imagem no quadro branco de um processador com um fuso de fio saindo dele.

@TechnikEmpire Dê uma olhada neste intel.com/content/www/us/en/processors/core/… , talvez você possa entrar em contato com a intel e desenhá-los também.
G7k

24

O desempenho real dependerá do rendimento voluntário de cada thread. Por exemplo, se os encadeamentos NÃO tiverem E / S e não usarem serviços do sistema (ou seja, eles são 100% ligados à CPU), então um encadeamento por núcleo é o ideal. Se os encadeamentos fizerem algo que exija espera, será necessário experimentar para determinar o número ideal de encadeamentos. 4000 threads acarretariam uma sobrecarga significativa na programação, portanto provavelmente também não é o ideal.


21

A resposta depende da complexidade dos algoritmos usados ​​no programa. Eu vim com um método para calcular o número ideal de threads fazendo duas medições dos tempos de processamento Tn e Tm para dois números arbitrários de threads 'n' e 'm'. Para algoritmos lineares, o número ideal de encadeamentos será N = sqrt ((m n (Tm * (n-1) - Tn * (m-1))) / (n Tn-m Tm)).

Por favor, leia meu artigo sobre cálculos do número ideal para vários algoritmos: pavelkazenin.wordpress.com


4
Por que está com voto negativo? Sinto muito, mas esta é a melhor resposta para esta pergunta. gonzalo aborda a parte mais ousada da pergunta e pkazen aborda o título. Ambas as respostas são muito úteis, mas a resposta pkazen é relevante porque temos um método sistemático para aproximar o número de threads. Ele ainda dá a fórmula para algoritmos de linha.
tobiak777

1
Eu não diminuí a votação, mas se o fizesse seria com base em que não há explicação real sobre por que ou como o número ideal de threads pode estar relacionado à complexidade do algoritmo, exceto lendo o artigo inteiro, que é uma leitura longa (devido à complexidade do artigo). Além disso, alguns aspectos do artigo não estão claros para mim, principalmente como os resultados experimentais confirmam a teoria.
Codebling

Além disso, acredito que esse cálculo pressupõe que você tenha um número infinito de núcleos de CPU. Embora essas informações sejam definitivamente valiosas, a questão está se referindo a máquinas reais com um pequeno número de núcleos.
Navneeth 03/04/19

9

Eu pensei em adicionar outra perspectiva aqui. A resposta depende se a pergunta está assumindo escala fraca ou escala forte.

Da Wikipedia :

Escala fraca: como o tempo de solução varia com o número de processadores para um tamanho de problema fixo por processador.

Escala forte: como o tempo de solução varia com o número de processadores para um tamanho total fixo do problema.

Se a pergunta está assumindo escala fraca, a resposta de @ Gonzalo é suficiente. No entanto, se a pergunta estiver assumindo uma escala forte, há algo a acrescentar. Em escala forte, você assume um tamanho fixo de carga de trabalho; portanto, se você aumentar o número de threads, o tamanho dos dados nos quais cada thread precisa trabalhar diminui. Nas CPUs modernas, os acessos à memória são caros e seria preferível manter a localidade mantendo os dados em caches. Portanto, o número ideal provável de threads pode ser encontrado quando o conjunto de dados de cada thread se encaixa no cache de cada núcleo (não entrarei em detalhes para discutir se é o cache L1 / L2 / L3 do sistema).

Isso vale mesmo quando o número de threads excede o número de núcleos. Por exemplo, suponha que haja 8 unidades arbitrárias (ou AU) de trabalho no programa que serão executadas em uma máquina de 4 núcleos.

Caso 1: execute com quatro threads em que cada thread precisa concluir 2AU. Cada thread leva 10s para ser concluído ( com muitas falhas de cache ). Com quatro núcleos, o tempo total será de 10s (10s * 4 threads / 4 núcleos).

Caso 2: execute com oito threads em que cada thread precisa concluir 1AU. Cada encadeamento leva apenas 2s (em vez de 5s devido à quantidade reduzida de erros de cache ). Com quatro núcleos, o tempo total será de 4s (2s * 8 threads / 4 núcleos).

Simplifiquei o problema e ignorei as despesas gerais mencionadas em outras respostas (por exemplo, alternâncias de contexto), mas espero que você entenda que pode ser benéfico ter mais número de threads do que o número disponível de núcleos, dependendo do tamanho dos dados ' está lidando com.


7

4000 threads ao mesmo tempo é bastante alto.

A resposta é sim e não. Se você estiver executando muitas E / S de bloqueio em cada encadeamento, sim, poderá mostrar acelerações significativas fazendo provavelmente 3 ou 4 encadeamentos por núcleo lógico.

Se você não estiver bloqueando muitas coisas, no entanto, a sobrecarga extra com a segmentação apenas a tornará mais lenta. Portanto, use um perfilador e veja onde estão os gargalos em cada peça possivelmente paralela. Se você estiver fazendo cálculos pesados, mais de 1 thread por CPU não ajudará. Se você estiver transferindo muita memória, também não ajudará. Se você estiver executando muitas E / S, como acesso ao disco ou à Internet, sim, vários threads ajudarão até certo ponto ou, pelo menos, tornarão o aplicativo mais responsivo.


7

Referência.

Eu começava a aumentar o número de threads para um aplicativo, começando em 1, e depois chegava a algo como 100, executava três e cinco tentativas para cada número de threads e desenvolvia um gráfico da velocidade de operação versus número de threads. .

Você deve considerar que a caixa de quatro threads é ideal, com leves aumentos no tempo de execução depois disso, mas talvez não. Pode ser que seu aplicativo seja limitado por largura de banda, ou seja, o conjunto de dados que você está carregando na memória é enorme, você está recebendo muitas falhas de cache etc., de modo que 2 threads são ideais.

Você não pode saber até testar.


3

Você encontrará quantos threads você pode executar em sua máquina executando o comando htop ou ps que retorna o número de processos em sua máquina.

Você pode usar a página de manual sobre o comando 'ps'.

man ps

Se você deseja calcular o número de processos de todos os usuários, pode usar um destes comandos:

  1. ps -aux| wc -l
  2. ps -eLf | wc -l

Calculando o número de um processo do usuário:

  1. ps --User root | wc -l

Além disso, você pode usar "htop" [Referência] :

Instalando no Ubuntu ou Debian:

sudo apt-get install htop

Instalando no Redhat ou CentOS:

yum install htop
dnf install htop      [On Fedora 22+ releases]

Se você deseja compilar o htop a partir do código fonte, você o encontrará aqui .


2

O ideal é 1 thread por núcleo, desde que nenhum deles bloqueie.

Um caso em que isso pode não ser verdade: existem outros threads em execução no núcleo; nesse caso, mais threads podem fornecer ao seu programa uma fatia maior do tempo de execução.


Depende se você deseja que os processos em segundo plano dos usuários sejam executados como lixo enquanto o aplicativo está sendo executado. Nesse caso, você pode apenas definir uma prioridade em tempo real para cada thread e obter a quantidade máxima de energia. Mas os usuários gostam de multitarefa.
Earlz

2
Bem, estamos lidando com uma aplicação mágica idealmente paralelelizável. Se alguma vez eu criasse algo assim, teria o direito de consumir a CPU o quanto quisesse.
Patros

2

Um exemplo de muitos threads ("pool de threads") versus um por núcleo é o da implementação de um servidor Web no Linux ou no Windows.

Como os soquetes são pesquisados ​​no Linux, muitos threads podem aumentar a probabilidade de um deles pesquisar o soquete certo no momento certo - mas o custo geral de processamento será muito alto.

No Windows, o servidor será implementado usando portas de conclusão de E / S - IOCPs - que farão com que o aplicativo seja acionado: se uma E / S for concluída, o SO iniciará um thread em espera para processá-lo. Quando o processamento é concluído (geralmente com outra operação de E / S como em um par de solicitação-resposta), o encadeamento retorna à porta IOCP (fila) para aguardar a próxima conclusão.

Se nenhuma E / S foi concluída, não há processamento a ser feito e nenhum encadeamento é iniciado.

De fato, a Microsoft recomenda não mais que um thread por núcleo nas implementações do IOCP. Qualquer E / S pode ser conectada ao mecanismo IOCP. Os COI também podem ser publicados pelo aplicativo, se necessário.


Não sei de qual Linux você está falando, mas meus bloqueios até a conexão chegar. Eu sugiro que você leia algumas coisas sobre select () e FD_SET () e funções / macros similares.
Alexis Wilke

Ok, então não há formulário assíncrono que retorne imediatamente?
Olof Forshell

Na página do manual select ():timeout is an upper bound on the amount of time elapsed before select() returns. If both fields of the timeval structure are zero, then select() returns immediately. (This is useful for polling.) If timeout is NULL (no timeout), select() can block indefinitely.
Alexis Wilke

0

falando do ponto de vista da computação e da memória vinculada (computação científica), 4000 threads tornarão o aplicativo muito lento. Parte do problema é uma sobrecarga muito alta da alternância de contexto e, provavelmente, uma localização de memória muito ruim.

Mas isso também depende da sua arquitetura. De onde ouvi os processadores Niagara, supostamente, são capazes de lidar com vários threads em um único núcleo usando algum tipo de técnica avançada de pipelining. No entanto, não tenho experiência com esses processadores.


0

Espero que isso faça sentido, verifique a utilização da CPU e da memória e coloque algum valor limite. Se o valor limite for ultrapassado, não permita criar novo encadeamento, senão permita ...

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.