Você vê essa frase ou algo semelhante de vez em quando, geralmente referindo-se a um programa que afirma que não foi projetado para aproveitar ao máximo os processadores com vários núcleos. Isso é comum, especialmente com a programação de videogames. (é claro que muitos programas não têm simultaneidade e não precisam dele, como scripts básicos, etc.).
Como isso pode ser? Muitos programas (especialmente jogos) usam inerentemente a simultaneidade e, como o sistema operacional é responsável pelo agendamento de tarefas na CPU, esses programas não estão tirando proveito inerente dos vários núcleos disponíveis? O que significaria neste contexto "tirar proveito de múltiplos núcleos"? Esses desenvolvedores estão realmente proibindo o agendamento de tarefas do SO e forçando a afinidade ou o próprio agendamento? (Parece um grande problema de estabilidade).
Eu sou um programador Java, então talvez eu não tenha tido que lidar com isso devido a abstrações ou outros enfeites.
fonte
Respostas:
Uma boa concorrência requer muito mais do que lançar alguns threads em um aplicativo e esperar o melhor. Há uma variedade de como um programa simultâneo pode passar de embaraçosamente paralelo a puro seqüencial. Qualquer programa pode usar a lei de Amdahl para expressar quão escalável é um problema ou algoritmo. Algumas qualificações para uma aplicação embaraçosamente paralela seriam:
Existem outras qualificações, mas com apenas essas duas podemos entender por que os jogos em particular não são tão fáceis quanto você imagina para tirar proveito de múltiplos núcleos. Por um lado, o modelo do mundo que será renderizado deve ser compartilhado, pois diferentes funções calculam física, movimento, aplicam inteligência artificial etc. Segundo, cada quadro deste modelo de jogo deve ser renderizado na tela com uma placa gráfica.
Para ser justo, muitos criadores de jogos usam mecanismos de jogos produzidos por terceiros. Demorou um pouco, mas esses mecanismos de jogos de terceiros agora são muito mais paralelos do que costumavam ser.
Existem desafios arquitetônicos maiores ao lidar com simultaneidade eficaz
A simultaneidade pode assumir várias formas, desde a execução de tarefas em segundo plano até um suporte arquitetural completo para simultaneidade. Alguns idiomas oferecem recursos de simultaneidade muito poderosos, como o ERLANG , mas exige que você pense de maneira muito diferente sobre como você constrói seu aplicativo.
Nem todo programa realmente precisa da complexidade do suporte multicore completo. Um exemplo é o software tributário ou qualquer aplicativo orientado a formulários. Quando a maior parte do tempo é gasta esperando o usuário fazer alguma coisa, a complexidade dos aplicativos multithread não é tão útil.
Alguns aplicativos se prestam a uma solução paralela mais embaraçosa, como aplicativos da web. Nesse caso, a plataforma começa embaraçosamente paralela e você não precisa impor a contenção de threads.
A linha inferior:
Nem todos os aplicativos são realmente prejudicados por não aproveitarem vários threads (e, portanto, núcleos). Para aqueles que são prejudicados por isso, às vezes os cálculos não são amigáveis ao processamento paralelo ou a sobrecarga para coordenar isso tornaria o aplicativo mais frágil. Infelizmente, o processamento paralelo ainda não é tão fácil quanto deveria ser.
fonte
Não, na verdade é o contrário. A maioria dos aplicativos é gravada em uma única mentalidade encadeada e o (s) desenvolvedor (es) nunca fez as alterações necessárias para oferecer suporte à simultaneidade.
Em C, C ++ e C #, você precisa informar explicitamente ao aplicativo para iniciar novos threads e / ou processos.
Eu acho que você está se concentrando demais no agendamento dos threads e não o suficiente na manipulação de dados nos possíveis threads. Compartilhar dados entre threads e / ou processos requer alguma forma de sincronização. Se você alterar um aplicativo para usar vários encadeamentos, mas falhar na sincronização, provavelmente verá muito difícil rastrear bugs no código.
Para os aplicativos multithread em que trabalhei, geralmente nunca me preocupei com o envio e apenas com a sincronização de dados. As únicas vezes em que tive que me preocupar com a expedição foi quando estava perseguindo as condições de corrida devido à sincronização incorreta dos dados.
Geralmente, quando um aplicativo diz que não pode usar vários núcleos, significa que eles não têm a sincronização para proteger a manipulação de dados.
fonte
Não se trata tanto de múltiplos núcleos, mas de vários threads. O sistema operacional pode agendar um encadeamento para execução em qualquer núcleo que desejar, e esse agendamento é transparente para o programa que está sendo agendado. No entanto, muitos programas não são gravados usando vários encadeamentos, portanto, eles podem ser executados apenas em um núcleo por vez.
Por que eu escreveria um programa de thread único? Eles são mais fáceis de escrever e mais fáceis de depurar: uma coisa acontece após a outra (em vez de várias coisas acontecerem ao mesmo tempo e possível se interpor). Ou seu programa pode não ter como alvo máquinas com vários núcleos (como foi o caso de jogos antigos). Em alguns casos, um programa multithread pode até rodar mais lentamente que uma versão single threaded se a sobrecarga das alternâncias de contexto e a comunicação entre threads exceder a velocidade obtida pela execução paralela (algumas partes do programa podem não ser paralelizáveis).
fonte
Esta não é uma resposta completa. É um conto de advertência.
Um dia, pensei em mostrar aos alunos do meu curso de programação simultâneo uma classificação rápida paralela. O mercúrio deve ser bem paralelo, pensei. Eu usei dois threads. Executei no meu computador single core. Os resultados foram:
Era sobre o que eu esperava.
Então eu tentei em uma máquina mais nova de núcleo duplo.
Os dois threads compartilharam uma fila de tarefas restantes. Parece que os campos do objeto de fila estavam sendo embaralhados entre o cache de um núcleo e o outro.
fonte