Capítulo 1 Introdução
A computação paralela e distribuída é uma realidade em todas as áreas de pesquisa aplicadas. À primeira vista, pode-se esperar que as aplicações se beneficiam diretamente do ganho em poder computacional. Afinal, se a carga (processo) computacional de uma aplicação for repartida e distribuída em  processadores (instâncias de processamentos, threads ou cores), a computação paralela deve ocorrer em um tempo menor do que se a aplicação fosse computada em um único processador (em serial). Entretanto, a tarefa de repartir e distribuir (alocação de tarefas) o processo computacional de uma aplicação é, em muitos casos, bastante desafiadora e pode, em vários casos, levar a códigos computacionais menos eficientes que suas versões seriais.
 
Repartir e distribuir o processo computacional de uma aplicação sempre é possível, mas nem sempre é possível a computação paralela de cada uma das partes. Por exemplo, vamos considerar a iteração de ponto fixo
|  |  |  | (1.1) | 
|  |  |  | (1.2) | 
onde  é uma função dada e  é o ponto inicial da iteração. Para computar  devemos processar  vezes a iteração (1.1). Se tivéssemos a disposição  processadores, poderíamos repartir a carga de processamento em dois, distribuindo o processamento das  primeiras iterações para o primeiro processador (o processador ) e as demais  para o segundo processador (o processador ). Entretanto, pela característica do processo iterativa, o processador  ficaria ocioso, aguardando o processador  computar . Se ambas instâncias de processamento compartilharem a mesma memória computacional (memória compartilhada), então, logo que o processador  computar  ele ficará ocioso, enquanto que o processador  computará as últimas  iterações. Ou seja, esta abordagem não permite a computação em paralelo, mesmo que reparta e distribua o processo computacional entre duas instâncias de processamento.
 
Ainda sobre a abordagem acima, caso as instâncias de processamento sejam de memória distribuída (não compartilhem a mesma memória), então o processador  e o processador  terão de se comunicar, isto é, o processador  deverá enviar  para a instância de processamento  e esta instância deverá receber  para, então, iniciar suas computações. A comunicação entre as instâncias de processamento levantam outro desafio que é necessidade ou não da sincronização () eventual entre elas. No caso de nosso exemplo, é a necessidade de sincronização na computação de  que está minando a computação paralela.
 
Em resumo, o design de métodos numéricos paralelos deve levar em consideração a alocação de tarefas, a comunicação e a sincronização entre as instâncias de processamentos. Vamos voltar ao caso da iteração (1.1). Agora, vamos supor que ,  e a condição inicial  é dada. No caso de termos duas instâncias de processamentos disponíveis, podemos computar as iterações em paralelo da seguinte forma. Iniciamos distribuindo  às duas instâncias de processamento  e . Em paralelo, a instância  computa  e a instância  computa . Para computar a nova iterada , a instância  precisa ter acesso a  e a instância  necessita de . Isto implica na sincronização das instâncias de processamentos, pois uma instância só consegui seguir a computação após a outra instância ter terminado a computação da mesma iteração. Agora, a comunicação entre as instâncias de processamento, depende da arquitetura do máquina. Se as instâncias de processamento compartilham a mesma memória (memória compartilhada), cada uma tem acesso direto ao resultado da outra. No caso de uma arquitetura de memória distribuída, ainda há a necessidade de instruções de comunicação entre as instância, i.e. a instância  precisa enviar  à instância , a qual precisa receber o valor enviado. A instância  precisa enviar  à instância , a qual precisa receber o valor enviado. O processo segue análogo para cada iteração até a computação de .
 
A primeira parte destas notas de aula, restringe-se a implementação de métodos numéricos paralelos em uma arquitetura de memória compartilhada. Os exemplos computacionais são apresentados em linguagem C/C++ com a interface de programação de aplicações (API, Application Programming Interface) OpenMP. A segunda parte, dedica-se a implementação paralela em arquitetura de memória distribuída. Os códigos C/C++ são, então, construídos com a API OpenMPI.