Como programar a alocação de threads em processadores multicore?

13

Eu gostaria de experimentar threads em um processador com vários núcleos, por exemplo, para criar um programa que usa dois threads diferentes que são executados por dois núcleos de processador diferentes.

No entanto, não está claro para mim em que nível os threads são alocados para os diferentes núcleos. Eu posso imaginar os seguintes cenários (dependendo do sistema operacional e da implementação da linguagem de programação):

  1. A alocação de encadeamentos é gerenciada pelo sistema operacional. Os threads são criados usando chamadas do sistema OS e, se o processo for executado em um processador com vários núcleos, o sistema operacional automaticamente tenta alocar / agendar segmentos diferentes em núcleos diferentes.
  2. A alocação de encadeamentos é gerenciada pela implementação da linguagem de programação. A alocação de encadeamentos em núcleos diferentes requer chamadas especiais do sistema, mas as bibliotecas de encadeamentos padrão da linguagem de programação tratam disso automaticamente quando eu uso a implementação de encadeamento padrão para essa linguagem.
  3. A alocação de encadeamentos deve ser programada explicitamente. No meu programa, tenho que escrever um código explícito para detectar quantos núcleos estão disponíveis e alocar segmentos diferentes para diferentes núcleos usando, por exemplo, funções de biblioteca.

Para tornar a pergunta mais específica, imagine que eu escrevi meu aplicativo multithread em Java ou C ++ no Windows ou Linux. Meu aplicativo verá e usará magicamente vários núcleos quando executado em um processador com vários núcleos (porque tudo é gerenciado pelo sistema operacional ou pela biblioteca de threads padrão) ou tenho que modificar meu código para estar ciente dos vários núcleos ?

Giorgio
fonte

Respostas:

11

Meu aplicativo verá e usará magicamente vários núcleos quando executado em um processador com vários núcleos (porque tudo é gerenciado pelo sistema operacional ou pela biblioteca de threads padrão) ou tenho que modificar meu código para estar ciente dos vários núcleos ?

Resposta simples: Sim, geralmente será gerenciado pelo sistema operacional ou pela biblioteca de threads.

O subsistema de encadeamento no sistema operacional atribuirá encadeamentos aos processadores com prioridade (sua opção 1). Em outras palavras, quando um encadeamento termina de executar sua alocação de tempo ou blocos, o planejador procura o próximo encadeamento de maior prioridade e o atribui à CPU. Os detalhes variam de sistema operacional para sistema operacional.

Dito isto, as opções 2 (gerenciadas pela linguagem de programação) e 3 (explicitamente) existem. Por exemplo, a biblioteca de tarefas e async / wait nas versões recentes do .Net oferecem ao desenvolvedor uma maneira muito mais fácil de escrever um código paralelizável (isto é, que pode ser executado simultaneamente com ele mesmo). As linguagens de programação funcional são eternamente paralelizáveis ​​e alguns tempos de execução executam diferentes partes do programa em paralelo, se possível.

Quanto à opção 3 (explicitamente), o Windows permite definir a afinidade do encadeamento (especificando em quais processadores um encadeamento pode ser executado). No entanto, isso geralmente é desnecessário em todos, exceto nos sistemas mais rápidos e críticos em tempo de resposta. A alocação efetiva de encadeamento para processador depende muito do hardware e é muito sensível a outros aplicativos em execução simultaneamente.

Se você quiser experimentar, crie uma tarefa demorada e com muita CPU, como gerar uma lista de números primos ou criar um conjunto Mandelbrot. Agora crie dois threads na sua biblioteca favorita e execute os dois threads em uma máquina com vários processadores (em outras palavras, praticamente qualquer coisa lançada nos últimos anos). Ambas as tarefas devem ser concluídas aproximadamente ao mesmo tempo, porque são executadas em paralelo.

Akton
fonte
Obrigado pela explicação (+1). Meu programa de teste é uma implementação de classificação por mesclagem. Na fase de divisão, quero criar threads diferentes, desde que haja núcleos disponíveis. Por exemplo, com dois núcleos, cada metade de uma matriz seria classificada por um segmento / núcleo diferente. Durante a mesclagem, os segmentos supérfluos seriam unidos / finalizados.
Giorgio
É difícil organizar a classificação dessa maneira se os dados forem distribuídos aleatoriamente. Sim, você pode separá-lo e, em seguida, classificar cada parte em um segmento diferente, mas eventualmente precisará mesclar todas as partes. Se os threads estiverem compartilhando estruturas de dados, você também poderá obter problemas de contenção ou bloqueio. Não estou dizendo que a classificação não pode se beneficiar da segmentação, mas não será uma melhoria linear no desempenho.
Akton
As duas metades de uma matriz podem ser classificadas independentemente, porque nenhum dado é compartilhado. Somente a primeira divisão e a última mesclagem terão que ser executadas por um thread manipulando toda a matriz ou lista que contém os dados. Isso significa que uma varredura completa dos dados não pode ser executada em paralelo; todas as verificações restantes podem.
Giorgio
Claro, também considero seus exemplos como bons candidatos. Atualmente, estou mais familiarizado com a classificação de mesclagem (e eu implementei uma versão não paralela), o que (talvez) tornaria a classificação de mesclagem mais adequada para mim como primeira tentativa.
Giorgio
2
Eu acrescentaria a essa resposta que bons sistemas operacionais são inteligentes o suficiente para equilibrar o custo de atribuir uma tarefa a uma fatia de tempo em uma CPU ou núcleo diferente ao da fome de curto prazo. Nas arquiteturas onde importa, o resultado tende a se parecer com afinidade automagica. O sistema operacional foi desenvolvido para que todos os trabalhos sejam executados o mais rápido possível, e você pode estar se atirando no pé amarrando segmentos aos núcleos e prejudicando sua capacidade de tomar essas decisões.
Blrfl 01/01
-1

Uma vez eu tive um enorme ambiente SGI IRIX. Só para começar, escrevi um pequeno programa java com vários threads (que não fazia nada além de consumir ciclos de CPU) e criei 12 threads nele. O trabalho se estendeu por 12 CPUs na arquitetura NUMA. Pode ser que eu procure o programa e execute-o no Dell R910s e verifique ..

P. Prabhakar
fonte
3
Esta resposta realmente não adiciona muito à resposta existente. Talvez se você elaborou sobre por que a JVM nas roscas sistema SGI alocados para o núcleo ...
Jay Elston