Diferença entre programação paralela e simultânea?

44

Ao analisar a programação simultânea, dois termos são comumente usados, ou seja, simultâneo e paralelo.

E algumas linguagens de programação reivindicam especificamente suporte para programação paralela, como Java .

Isso significa que a programação paralela e simultânea são realmente diferentes?

nish1013
fonte
10
Sim, programação simultânea e paralela são diferentes. por exemplo, você pode ter dois threads (ou processos) executando simultaneamente no mesmo núcleo por meio da alternância de contexto. Quando os dois threads (ou processos) são executados em dois núcleos diferentes (ou processadores), você tem paralelismo. Portanto, no primeiro caso (simultaneidade), o paralelismo é apenas "virtual", enquanto no segundo você tem um verdadeiro paralelismo. Portanto, todo programa paralelo é simultâneo, mas o inverso não é necessariamente verdadeiro.
Massimo Cafaro
1
Tenha cuidado aqui. Você pode obter o mesmo resultado através do suporte a idiomas (por exemplo, estendendo um idioma com novas construções) ou usando uma abordagem de baixo nível (por exemplo, usando uma biblioteca, como no caso do MPI e do OpenMP). De qualquer forma, com processadores multicore atuais e sistemas operacionais com suporte a SMP, o programa que será concorrente se for executado em processadores antigos de núcleo único, poderá ser executado em paralelo se o SO agendar os encadeamentos de execução do programa em diferentes núcleos. Então, a distinção é um pouco "borrada" hoje em dia.
Massimo Cafaro
3
O que você usa para uma velocidade de latência constante de luz. Simultaneamente, você finge que a velocidade da latência da luz é um ciclo de relógio. Paralelamente, você assume que um servidor está ao lado; em distribuído, assume que um servidor está em Marte.
1
Robert Harper discute o problema em duas postagens do blog, "Paralelismo não é simultâneo" e "Paralelismo e simultaneidade revisitados" , que você pode verificar.
Basil

Respostas:

26

Distinga o paralelismo (usando unidades computacionais extras para fazer mais trabalho por unidade de tempo) da simultaneidade (gerenciando o acesso a recursos compartilhados). Ensine o paralelismo primeiro porque é mais fácil e ajuda a estabelecer uma mentalidade não seqüencial.

De "Uma introdução sofisticada ao paralelismo e simultaneidade de memória compartilhada", de Dan Grossman (versão de 16 de novembro de 2013)

Rafael
fonte
21

Além da resposta de Nish, deixe-me recomendar o livro de Simon Marlow sobre Programação Paralela e Concorrente em Haskell ou seu tutorial mais curto . Eles respondem à sua primeira pergunta da perspectiva de Haskell, para que possam ser mais adequados para leitores teoricamente inclinados (Haskell é uma linguagem de programação preguiçosa, puramente funcional e muito mais próxima da Matemática do que outras linguagens).

Citando a partir daí:

Em muitos campos, as palavras paralela e simultânea são sinônimos; não é assim na programação, onde eles são usados ​​para descrever conceitos fundamentalmente diferentes.

Um programa paralelo é aquele que utiliza uma multiplicidade de hardware computacional (por exemplo, múltiplos núcleos de processador) para executar o cálculo mais rapidamente. Diferentes partes da computação são delegadas a diferentes processadores executados ao mesmo tempo (em paralelo), para que os resultados possam ser entregues mais cedo do que se a computação tivesse sido executada sequencialmente.

Por outro lado, a simultaneidade é uma técnica de estruturação de programas na qual existem vários threads de controle. Notionalmente, os threads de controle são executados "ao mesmo tempo"; isto é, o usuário vê seus efeitos intercalados. Se eles realmente executam ao mesmo tempo ou não é um detalhe de implementação; um programa simultâneo pode ser executado em um único processador através da execução intercalada ou em vários processadores físicos.

Recomendo a leitura do restante do tutorial (p.4), mas deixe-me citar parte do restante desta seção, pois conecta os dois paradigmas de programação às características quantitativas e qualitativas dos programas, como eficiência, modularidade e determinismo.

Enquanto a programação paralela se preocupa apenas com eficiência, a programação simultânea se preocupa com a estruturação de um programa que precisa interagir com vários agentes externos independentes (por exemplo, o usuário, um servidor de banco de dados e alguns clientes externos). A simultaneidade permite que esses programas sejam modulares; o encadeamento que interage com o usuário é distinto do encadeamento que fala com o banco de dados. Na ausência de simultaneidade, esses programas precisam ser gravados com loops e retornos de chamada de eventos - na verdade, loops e retornos de chamada de eventos geralmente são usados ​​mesmo quando a simultaneidade está disponível, porque em muitos idiomas a simultaneidade é muito cara ou muito difícil para usar.

A noção de "threads de controle" não faz sentido em um programa puramente funcional, porque não há efeitos a serem observados e a ordem de avaliação é irrelevante. Portanto, a simultaneidade é uma técnica de estruturação para código eficaz; em Haskell, isso significa código na mônada de IO.

Uma distinção relacionada é entre modelos de programação determinísticos e não determinísticos. Um modelo de programação determinístico é aquele em que cada programa pode fornecer apenas um resultado, enquanto um modelo de programação não determinístico admite programas que podem ter resultados diferentes, dependendo de algum aspecto da execução. Modelos de programação simultâneos são necessariamente não determinísticos, porque devem interagir com agentes externos que causam eventos em momentos imprevisíveis. O não determinismo tem algumas desvantagens notáveis: os programas se tornam significativamente mais difíceis de testar e raciocinar.

Para programação paralela, gostaríamos de usar modelos de programação determinísticos, se possível. Como o objetivo é apenas chegar à resposta mais rapidamente, preferimos não tornar nosso programa mais difícil de depurar no processo. A programação paralela determinística é o melhor dos dois mundos: teste, depuração e raciocínio podem ser executados no programa seqüencial, mas o programa é executado mais rapidamente quando os processadores são adicionados. De fato, a maioria dos processadores de computador implementa o paralelismo determinístico na forma de pipelining e várias unidades de execução.

Embora seja possível fazer programação paralela usando simultaneidade, isso geralmente é uma má escolha, porque a simultaneidade sacrifica o determinismo. Em Haskell, os modelos de programação paralela são determinísticos. No entanto, é importante observar que os modelos determinísticos de programação não são suficientes para expressar todos os tipos de algoritmos paralelos; existem algoritmos que dependem do não determinismo interno, particularmente problemas que envolvem a busca de um espaço de solução. Em Haskell, essa classe de algoritmos é expressável apenas usando simultaneidade.

nickie
fonte
20

Concorrência e paralelismo diferem nos problemas que resolvem e causam, mas não são independentes.

Concorrência

Executar duas tarefas simultaneamente significa que etapas individuais de ambas as tarefas são executadas de maneira intercalada. Se você desconsiderar o paralelismo, poderá assumir que apenas uma instrução é executada a qualquer momento, mas você não tem (a priori) nenhuma garantia de qual tarefa será executada na próxima etapa.

Isso é útil em alguns aspectos:

  • Programação mais clara de tarefas independentes em um programa.
  • Permite lidar com E / S durante a computação (por exemplo, na GUI).
  • Permite a execução de mais de um programa por vez (simultaneidade no nível do SO).

Alguns dos principais desafios são:

  • Manter a consistência dos dados.
  • Evite deadlocks e livelocks .
  • Determine a semântica precisa dos processos simultâneos.
  • Determine as propriedades estáticas que garantem a correção.

Paralelismo

Executar duas tarefas em paralelo significa que as instruções são executadas ao mesmo tempo . Isso é útil principalmente para:

  • Melhore a taxa de transferência do sistema executando programas em paralelo (por exemplo, em sistemas com vários núcleos).
  • Melhore o tempo de execução de programas individuais utilizando várias CPUs ao mesmo tempo.
  • Utilize o IO em muitas máquinas (por exemplo, bancos de dados distribuídos).

Os principais desafios incluem:

  • Problemas de partição que permitem e desenvolvem algoritmos que podem empregar paralelismo.
  • Minimize dependências e comunicação entre as unidades de computação.
  • Todos os problemas trazidos pela simultaneidade: pelo menos do ponto de vista da memória, os programas paralelos parecem concorrentes devido à serialização dos acessos à memória.
  • Lide com suporte de hardware abaixo do ideal.

Veja também esta pergunta para distinguir computação paralela e distribuída.

Rafael
fonte
5

Uma resposta ligeiramente idealizada, talvez ...

  • A simultaneidade é uma propriedade de como um programa é escrito . Se um programa é gravado usando construções como garfos / junções, bloqueios, transações, operações atômicas de comparação e troca e assim por diante, ele é simultâneo.

  • Paralelismo é uma propriedade de como um programa é executado . Se um programa é executado em mais de uma unidade computacional simultaneamente, ele está sendo executado em paralelo.

John Wickerson
fonte
1

Há muitas respostas sobre isso, mas pode ser confuso. Eu gosto de pensar dessa maneira, e talvez ajude ?:

A programação simultânea é um código que não se importa com a ordem de execução. Java é uma linguagem ruim para programação simultânea, mas existem bibliotecas e estruturas para ajudar. O JavaScript é uma excelente linguagem para programação simultânea, e geralmente é difícil quando você deseja escrever algo que não é simultâneo (por exemplo, se você deseja forçar a ordem de execução). A programação simultânea é ótima para a programação orientada a eventos (onde a ordem de execução é determinada pelos ouvintes de eventos, como código em execução no navegador que atua quando você clica em um botão ou digita em uma caixa).

Um exemplo incluiria a criação de cem solicitações HTTP. No NodeJS, a solução mais simples é abrir todas as 100 solicitações de uma só vez com um método de retorno de chamada e, quando as respostas retornam, um método é executado a cada vez. Isso é programação simultânea. Em Ruby, a solução mais simples (mais comum) é abrir uma solicitação e manipular a resposta, abrir a próxima solicitação e manipular a resposta, etc. Para muitas solicitações, o NodeJS é mais fácil de fazer em tempo hábil, embora você precise cuidado para evitar martelar o servidor ou maximizar suas conexões de saída (fácil de fazer por engano). Você pode escrever o Ruby de maneira simultânea, mas não é assim que a maioria dos códigos do Ruby é escrita, e dói um pouco fazer isso.

Programação paralelaé um código que pode ser executado simultaneamente em vários threads ou processos. Isso permite otimizar o desempenho executando o código em várias CPUs (geralmente incluindo várias máquinas, como você faria com algo como Akka). Como o NodeJS não é multiencadeado e não há execução paralela, você não precisa se preocupar em escrever código thread-safe (e a maioria dos códigos JavaScript que eu vi não é thread-safe). Em Java, mesmo que a linguagem não torne a programação simultânea o padrão normal, a programação paralela é muito incorporada, e você frequentemente precisa se preocupar com a segurança do encadeamento. Se você estiver escrevendo um site em Java, normalmente isso será executado em um contêiner que executa cada solicitação em um thread separado na mesma memória,


Algumas das opções acima dependem do escopo e dos limites dos quais você está falando. Eu trabalho em sites. A maioria dos códigos Java que vejo não é programação simultânea. Certamente, se você diminuir o zoom o suficiente, a ordem solicitada pelo cliente não é importante, mas se você aumentar o zoom além disso, a ordem em que as coisas serão executadas será ditada pelo código. Mas o código é escrito para que as solicitações possam ser executadas em paralelo com muitos objetos compartilhados que devem ser seguros para threads.

Enquanto isso, a maioria dos códigos JavaScript que vejo é simultânea: está escrito de maneira que a ordem de execução não é importante em muitos níveis. Mas não foi escrito para oferecer suporte à execução paralela na memória compartilhada. Claro, você pode executar o mesmo código em paralelo em vários processos, mas os objetos não são compartilhados, portanto, não é uma programação paralela em nenhum sentido significativo.

Para leituras adicionais, eu realmente gosto das ilustrações na resposta superior a esta pergunta aqui: https://www.quora.com/What-are-the-differences-between-parallel-concurrent-and-asynchronous-programming

Jun-Dai Bates-Kobashigawa
fonte