Quanto esforço devemos gastar na programação de múltiplos núcleos?


12

Atualmente, os processadores estão ficando cada vez mais núcleos, o que me deixa pensando ...

Programadores, devemos nos adaptar a esse comportamento e gastar mais esforço na programação de múltiplos núcleos?

Até que ponto devemos fazer e otimizar isso? Fio? Afinidade? Otimizações de hardware? Algo mais?

Respostas:


15

Não importa o quão bom você seja, será improvável que você tenha um esquema melhor para gerenciar threads etc. do que as equipes que desenvolvem o idioma e o compilador em que está escrevendo seu código.

Se você precisar que seu aplicativo seja multiencadeado, crie os encadeamentos necessários e deixe o compilador e o SO continuar com seus trabalhos.

Você precisa estar ciente de como esses encadeamentos são gerenciados para poder fazer o melhor uso dos recursos. Não criar muitos threads é uma coisa que vem à mente como exemplo.

Você também precisa estar ciente do que está acontecendo (consulte o comentário de Lorenzo) para poder fornecer dicas para o gerenciamento de threads (ou substituí-lo em casos especiais), mas eu pensaria que esses seriam poucos e distantes.


3
Mas um encadeamento que salta continuamente de um núcleo para outro terá penalidades de desempenho (devido à falta de cache da CPU de primeiro e segundo nível), especialmente em arquiteturas nas quais duas matrizes físicas distintas são empregadas. No código intensivo multithread, a afinidade é uma coisa boa.
usar o seguinte comando

@ Lorenzo - Nesse caso, você precisará ver se pode amarrar o fio em um único núcleo - o que talvez seja um caso especial - mas interessante.
ChrisF

1
Não seria um movimento estranho para o sistema operacional alternar um segmento ativo de um núcleo para outro?
JBRWilkinson

Concordo com o @JBRWilkinson, a afinidade do segmento parece um trabalho do SO para mim.
Collin

1
@JBRWilkinson No linux (e acho que a maioria dos sistemas operacionais), os threads saltam entre os núcleos o tempo todo. A primeira razão é que você tem muito mais threads em geral do que núcleos. E se alguns tópicos morrem, você precisa se equilibrar. A segunda razão é que muitos threads estão inativos. E quando alguns acordam, o kernel pode pensar que um núcleo tem mais carga que outros e move um encadeamento, geralmente o seu encadeamento de computação da CPU. Em seguida, 2 threads de monitores da CPU são executados no mesmo núcleo até o kernel se mover um para trás. Se você estiver dividindo um trabalho grande em partes exatamente com núcleos, deseje definir a afinidade do encadeamento.
Goswin von Brederlow

5

Sou programador .NET e sei que o .NET possui uma abstração de alto nível para multithreading chamada Tasks. Ele protege você de ter que saber muito sobre como executar multithreading adequado contra o metal. Suponho que outras plataformas de desenvolvimento atuais tenham abstrações semelhantes. Portanto, se você quiser fazer algo com multithreading, tentarei trabalhar nesse nível, se possível.

Agora, para a questão de você deve se preocupar com multithreading em seu aplicativo em particular. A resposta a essa pergunta depende muito do aplicativo que você está escrevendo. Se você estiver escrevendo um aplicativo que processa milhares (ou mais) coisas independentes, e esse processamento pode ser feito em paralelo, você certamente obterá uma vantagem do multithreading. No entanto, se você estiver escrevendo uma tela simples de entrada de dados, o multithreading pode não lhe custar muito.

No mínimo, você precisa se preocupar com multithreading quando estiver trabalhando em uma interface do usuário. Você não deseja disparar uma operação de longa execução a partir da interface do usuário e deixar de responder porque você sequestrou o thread da interface do usuário para executar essa operação. Dispare um encadeamento em segundo plano e, pelo menos, dê ao usuário um botão Cancelar para que ele não precise esperar que ele seja concluído se cometer um erro.


5

Na terra do Objective-C e Mac OS X e iOS, as estruturas (como muitas outras) são escritas para aproveitar esses aumentos nos núcleos do processador e apresentar ao desenvolvedor uma boa interface para usá-los.

Exemplo no Mac OS X e iOS é o envio Grand Central. Existem adições a libc(acredito) para facilitar o multiencadeamento baseado em fila. Em seguida, as estruturas Cocoa e Foundation (entre outras) são escritas na parte superior do GCD, oferecendo ao desenvolvedor fácil acesso a filas de despacho e encadeamento com muito pouco código de placa de caldeira.

Muitas linguagens e estruturas têm conceitos semelhantes.


5

A parte difícil é dividir o algoritmo intensivo da CPU em pedaços de execução que podem ser encadeados.

Então, um encadeamento que salta continuamente de um núcleo para outro terá penalidades de desempenho (devido à falta de cache de CPU de primeiro e segundo nível), especialmente em arquiteturas nas quais duas matrizes físicas distintas são empregadas. Nesse caso, a afinidade do núcleo da thread é uma coisa boa.


3

Estamos agora (outubro de 2010) em um momento de imensa transição.

Hoje poderíamos comprar um desktop de 12 núcleos.
Hoje, poderíamos comprar um cartão de processamento de 448 núcleos (pesquise NVidia Tesla).

Existem limites para quanto nós, desenvolvedores, podemos trabalhar ignorando os ambientes tremendamente paralelos em que nossos programas trabalharão no futuro próximo.

Sistemas operacionais, ambientes de tempo de execução e bibliotecas de programação só podem fazer muito.

No futuro, precisaremos particionar nosso processamento em partes discretas para processamento independente, usando abstrações como o novo .NET "Task Framework".

Detalhes como gerenciamento de cache e afinidade ainda estarão presentes - mas serão a prova apenas do aplicativo com desempenho ultra-alto. Nenhum mesmo desenvolvedor desejará gerenciar esses detalhes manualmente em uma máquina com núcleo de 10k.


3

bem, realmente depende do que você está desenvolvendo. a resposta, dependendo do que você está desenvolvendo, pode variar de "é insignificante" a "é absolutamente crítico, e esperamos que todos na equipe tenham um bom entendimento e uso de implementações paralelas".

na maioria dos casos, um sólido entendimento e uso de bloqueios, encadeamentos e tarefas e conjuntos de tarefas será um bom começo quando a necessidade de paralelismo for necessária. (varia de acordo com lang / lib)

Acrescente a isso as diferenças de design que você deve fazer - para o multiprocessamento não trivial, é necessário aprender vários novos modelos de programação ou estratégias de paralelização. nesse caso, o tempo para aprender, para falhar o suficiente para ter um entendimento sólido e para atualizar os programas existentes pode levar uma equipe por ano (ou mais). depois de chegar a esse ponto, (espero!), você não perceberá nem abordará problemas / implementações como faz hoje (desde que ainda não tenha feito essa transição).

outro obstáculo é que você está efetivamente otimizando um programa para uma determinada execução. se você não tiver muito tempo para otimizar os programas, realmente não se beneficiará tanto quanto deveria. uma paralelização de alto nível (ou óbvia) pode melhorar a velocidade percebida do seu programa com bastante pouco esforço, e é o que muitas equipes vão fazer hoje: "Paralelizamos as partes realmente óbvias do aplicativo" - isso é bom em alguns casos. o benefício de pegar a fruta mais baixa e usar a paralelização simples será proporcional ao número de núcleos? muitas vezes, quando existem dois a quatro núcleos lógicos, mas não tão frequentemente além disso. em muitos casos, é um retorno aceitável, dado o investimento de tempo. esse modelo paralelo é a introdução de muitas pessoas para implementar bons usos do paralelismo.

o que você aprender usando esses modelos paralelos triviais não será ideal em todos os cenários paralelos complexos; A aplicação eficaz de projetos paralelos complexos requer uma compreensão e abordagem muito diferentes. esses modelos simples geralmente são desanexados ou têm interação trivial com outros componentes do sistema. também, muitas implementações desses modelos triviais não se adaptam bem a sistemas paralelos efetivamente complexos - um projeto paralelo complexo e ruim pode demorar tanto para ser executado quanto o modelo simples. doente: executa duas vezes mais rápido que o modelo de thread único, enquanto utiliza 8 núcleos lógicos durante a execução. os exemplos mais comuns estão usando / criando muitos threads e altos níveis de interferência de sincronização. em geral, isso é chamado de desaceleração paralela. é muito fácil encontrar se você abordar todos os problemas paralelos como problemas simples.

então, digamos que você realmente deva utilizar multithreading eficiente em seus programas (a minoria no clima de hoje): será necessário empregar o modelo simples de maneira eficaz para aprender o modelo complexo e, em seguida, reaprender como você aborda o fluxo e a interação do programa. o modelo complexo é onde seu programa deve estar, pois é onde o hardware está hoje e onde as melhorias mais dominantes serão feitas.

a execução de modelos simples pode ser vista como um garfo, e os modelos complexos operam como um ecossistema complexo. Eu acho que o entendimento de modelos simples, incluindo bloqueio geral e encadeamento, deve ou será esperado em breve para desenvolvedores intermediários quando o domínio (no qual você desenvolve) o usa. hoje, a compreensão de modelos complexos ainda é um pouco incomum (na maioria dos domínios), mas acho que a demanda aumentará rapidamente. como desenvolvedores, muito mais dos nossos programas devem oferecer suporte a esses modelos, e a maior parte do uso está muito atrasada na compreensão e implementação desses conceitos. Como a contagem lógica de processadores é uma das áreas mais importantes da melhoria de hardware, a demanda por pessoas que entendem e podem implementar sistemas complexos certamente aumentará.

finalmente, muitas pessoas pensam que a solução é apenas "adicionar paralelização". muitas vezes, é melhor acelerar a implementação existente. é muito mais fácil e muito mais direto em muitos casos. muitos programas na natureza nunca foram otimizados; algumas pessoas tiveram a impressão de que a versão não otimizada seria ofuscada pelo hardware em breve. melhorar o design ou algos dos programas existentes também é uma habilidade importante se o desempenho for importante - jogar mais núcleos nos problemas não é necessariamente a melhor ou mais simples solução.

Ao direcionar PCs modernos, a maioria de nós que precisa implementar bons sistemas paralelos não precisará ir além de multithreading, bloqueio, bibliotecas paralelas, livros que valem a pena ler e muita experiência em escrever e testar programas (basicamente, reestruturando significativamente como você programas de escrita de abordagem).


2

Fazemos, mas escrevemos software pesado de cálculo para nos beneficiarmos diretamente de vários núcleos.

Às vezes, o agendador move muito os threads entre os núcleos. Se isso não for aceitável, você pode jogar com a afinidade principal.


0

Tal como está, a frequência do processador não aumentará no futuro próximo. Estamos presos em torno da marca de 3 GHz (sem overclock). Certamente, para muitas aplicações, pode não ser necessário ir além da multithread muito básica. Obviamente, se você estiver criando um aplicativo de interface com o usuário, qualquer processamento intensivo deve ser feito em um encadeamento em segundo plano.

Se você estiver criando um aplicativo que está processando grandes quantidades de dados que precisam ser em tempo real, então sim, provavelmente deve analisar a programação com vários threads.

Para programação multiencadeada, você encontrará retornos decrescentes no desempenho; você pode passar horas e melhorar o programa em 15% e, em seguida, passar mais uma semana e apenas melhorá-lo em mais 5%.

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.