Como posso ter threads 1805 quando tenho apenas 4 CPUs virtuais?

10

Fiquei me perguntando se alguém poderia me explicar como, no Monitor de Atividade, ele diz que atualmente tenho 1805 threads Captura de tela do OS X Activity Monitor

Mas eu tenho apenas quatro núcleos virtuais no meu computador (o que significa que só posso ter quatro threads). A contagem de threads significa todos os threads que estão sendo manipulados pelas CPUs quando eles decidem qual thread executar?

EDIT: A razão que eu acho que só pode haver 4 threads na minha máquina vem desta resposta . Acredito que meu mal-entendido decorre da palavra 'thread' ser usada em um contexto diferente.

Amarela
fonte
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
bmike

Respostas:

24

Agendamento

Seus 1.805 threads não são executados simultaneamente . Eles trocam. Um núcleo executa um pouco do encadeamento e o coloca de lado para executar um pouco de outro encadeamento. Os outros núcleos fazem o mesmo. Rodando e rodando, os threads são executados um pouco de cada vez, não todos de uma vez.

Uma das principais responsabilidades do sistema operacional (Darwin e macOS) é o agendamento de qual thread deve ser executado em qual núcleo por quanto tempo.

Muitos threads não têm trabalho a fazer e, portanto, são deixados inativos e não programados. Da mesma forma, muitos encadeamentos podem estar aguardando algum recurso, como dados a serem recuperados do armazenamento, uma conexão de rede concluída ou dados a serem carregados de um banco de dados. Com quase nada a fazer além de verificar o status do recurso esperado, esses encadeamentos são agendados brevemente, se houver.

O programador de aplicativos pode ajudar nessa operação de agendamento adormecendo seu encadeamento por um certo período de tempo, quando sabe que a espera pelo recurso externo levará algum tempo. E se estiver executando um loop "apertado", que consome muita CPU, sem motivo para esperar por recursos externos, o programador pode inserir uma chamada para que o voluntário seja retirado brevemente, para não sobrecarregar o núcleo e, assim, permitir que outros threads sejam executados.

Para mais detalhes, consulte a página da Wikipedia para multithreading .

Multi-rosqueamento simultâneo

Quanto à sua pergunta vinculada , os tópicos de fato são os mesmos que aqui.

Um problema é o custo adicional de alternar entre threads quando agendado pelo sistema operacional. Há um custo significativo no tempo para descarregar as instruções e os dados do encadeamento atual do núcleo e, em seguida, carregar as instruções e os dados do próximo encadeamento agendado. Parte do trabalho do sistema operacional é tentar ser inteligente ao agendar os encadeamentos para otimizar esse custo adicional.

Alguns fabricantes de CPU desenvolveram tecnologia para reduzir esse tempo, de modo a tornar a alternância entre um par de threads muito mais rápida. A Intel chama sua tecnologia de Hyper-Threading . Conhecida genericamente como multi-threading simultâneo (SMT) .

Embora o par de encadeamentos não seja executado simultaneamente, a alternância é tão suave e rápida que os dois encadeamentos parecem praticamente simultâneos. Isso funciona tão bem que cada núcleo se apresenta como um par de núcleos virtuais no sistema operacional. Portanto, uma CPU habilitada para SMT com quatro núcleos físicos, por exemplo, se apresentará ao sistema operacional como uma CPU de oito núcleos.

Apesar dessa otimização, ainda há alguma sobrecarga na alternância entre esses núcleos virtuais. Muitos encadeamentos intensivos da CPU, todos exigindo que o tempo de execução seja agendado em um núcleo, podem tornar o sistema ineficiente, sem que nenhum encadeamento faça muito trabalho. Como três bolas em um playground sendo compartilhadas entre nove crianças, em vez de compartilhar entre novecentas crianças, onde nenhuma criança realmente se diverte com uma bola.

Portanto, existe uma opção no firmware da CPU em que um administrador de sistemas pode ativar um comutador na máquina para desativar o SMT se ela decidir que isso beneficiaria seus usuários executando um aplicativo que é incomumente vinculado à CPU com muito poucas oportunidades de pausa.

Nesse caso, voltamos à sua pergunta original: nessa situação especial, você realmente deseja restringir as operações a não ter mais desses segmentos hiperativos do que os núcleos físicos. Mas deixe-me repetir: essa é uma situação extremamente incomum que pode ocorrer em algo como um projeto científico de processamento de dados científicos, mas quase nunca se aplica a cenários comuns de negócios / empresas / empreendimentos.

Basil Bourque
fonte
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
bmike
Além disso, ninguém coloca yield()chamadas de sistema em seus threads intensivos de CPU (a menos que seja um código legado da multitarefa cooperativa no Classic MacOS). Reprogramações multitarefas preventivas após um segmento esgotar sua fatia de tempo.
Peter Cordes
Sua descrição do hyperthreading está errada. Threads de hardware! = Threads de software, são contextos de execução / núcleos lógicos. Ambos os núcleos lógicos em um núcleo físico realmente executam suas instruções ao mesmo tempo. O front-end alterna entre threads (cada ciclo), mas o núcleo de execução fora de ordem pode executar instruções / alterações de ambos os threads no mesmo ciclo. Isso expõe o paralelismo no nível de instrução de dois threads à execução de OoO para manter melhor as unidades de execução alimentadas com trabalho (esse é basicamente o ponto do SMT). Não é apenas "troca de contexto otimizada".
Peter Cordes
en.wikipedia.org/wiki/Hyper-threading possui um diagrama. Veja também o genérico en.wikipedia.org/wiki/Simultaneous_multithreading
Peter Cordes
7

Antigamente - a memória não era virtualizada ou protegida e qualquer código podia escrever em qualquer lugar. Naqueles dias, um thread para um design de CPU fazia sentido. Nas décadas seguintes, a memória foi protegida e depois virtualizada. Pense nos encadeamentos como núcleos virtuais - meio que uma promessa de que, em algum momento em que seus dados e código estavam prontos, esse encadeamento é enviado ( ou agendado como os engenheiros de PHD e matemáticos que pesquisam algoritmos de agendamento ) em uma CPU real para faça um trabalho real.

insira a descrição da imagem aqui

Agora - devido às magnitudes das diferenças de tempo - a CPU e o cache operam tão rápido em comparação com a obtenção de dados do armazenamento ou da rede -, milhares de threads podem ir e vir enquanto um thread aguarda www.google.com para fornecer um pacote ou dois de dados, é por isso que você vê muito mais threads do que a CPU real.

Se você converter as operações de encadeamento que ocorrem na escala de tempo preto / azul e convertê-las em um segundo = 1 ns, as coisas com as quais nos preocupamos são mais como E / S de disco. Atraso de 20 anos se você estiver contando segundos na escala de tempo da CPU. Como muitos poderes de dez exercícios , em quase todos os casos - a CPU fica ociosa por "meses" esperando um trabalho significativo de um mundo externo muito, muito lento.

Nada parece errado na imagem que você postou, então talvez estejamos entendendo mal o que você está perguntando sobre tópicos.

Se você clicar com o botão direito do mouse (clique de controle) na palavra threads na linha do cabeçalho na parte superior, adicione o status do aplicativo e verá que a maioria dos threads provavelmente está ociosa, inativa, não sendo executada em nenhum momento.

bmike
fonte
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
bmike
1

Você não faz a pergunta sem dúvida mais fundamental: "Como posso ter 290 processos quando minha CPU possui apenas quatro núcleos?" Esta resposta é um pouco histórica, o que pode ajudá-lo a entender o panorama geral, mesmo que a pergunta específica já tenha sido respondida. Como tal, não darei uma versão TL; DR.

Era uma vez (pense nos anos 50-60), os computadores só podiam fazer uma coisa de cada vez. Eles eram muito caros, enchiam salas inteiras e precisávamos de uma maneira de usá-los com eficiência, compartilhando-os entre várias pessoas. A primeira maneira de fazer isso era o processamento em lote , no qual os usuários enviavam tarefas ao computador e eram colocados em fila, executados um após o outro e os resultados eram enviados de volta ao usuário. Tudo bem, mas significava que, se você quisesse fazer um cálculo que levaria alguns dias, ninguém mais poderia usar o computador durante esse período.

A próxima inovação (pense nos anos 1960-70) foi o compartilhamento de tempo . Agora, em vez de executar a tarefa inteira, e depois a próxima, o computador executaria um pouco de uma tarefa, depois a pausaria e executaria um pouco da próxima, e assim por diante. Assim, o computador daria a impressão de que estava executando vários processos simultaneamente. A grande vantagem disso é que agora você pode executar um cálculo que levará alguns dias e, embora demore ainda mais, porque continua sendo interrompido, outras pessoas ainda podem usar a máquina durante esse período.

Tudo isso foi para grandes computadores no estilo mainframe. Quando os computadores pessoais começaram a se popularizar, eles inicialmente não eram muito poderosos e, como eram pessoais , parecia bom para eles conseguirem fazer apenas uma coisa & nbdp; - executar um aplicativo - ao mesmo tempo (pense nos anos 80). Mas, à medida que se tornaram mais poderosos (pense nos anos 90 até o presente), as pessoas queriam que seus computadores pessoais também compartilhassem tempo.

Por isso, acabamos com computadores pessoais que deram a ilusão de executar vários processos simultaneamente, executando-os um de cada vez por breves períodos e depois pausando-os. Threads são essencialmente a mesma coisa: eventualmente, as pessoas queriam até processos individuais para dar a ilusão de fazer várias coisas simultaneamente. No início, o criador do aplicativo tinha que lidar com isso: gastar um pouco atualizando os gráficos, pausar isso, gastar um pouco de cálculo, pausar isso, passar um pouco fazendo outra coisa, ...

No entanto, o sistema operacional já era bom em gerenciar vários processos; fazia sentido estendê-lo para gerenciar esses subprocessos, chamados de threads. Portanto, agora, temos um modelo em que todo processo (ou aplicativo) contém pelo menos um encadeamento, mas alguns contêm vários ou muitos. Cada um desses segmentos corresponde a uma subtarefa um tanto independente.

Mas, no nível superior, a CPU ainda está apenas dando a ilusão de que esses threads estão todos executando ao mesmo tempo. Na realidade, ele roda um por um tempo, faz uma pausa, escolhe outro para rodar um pouco, e assim por diante. Exceto que as CPUs modernas podem executar mais de um thread de uma vez. Então, na realidade real , o sistema operacional está jogando esse jogo de "corra um pouco, faça uma pausa, corra outra coisa um pouco, faça uma pausa" em todos os núcleos simultaneamente. Portanto, você pode ter quantos threads quiser (e os designers de aplicativos), mas, a qualquer momento, todos, com exceção de alguns, serão pausados.

David Richerby
fonte