As respostas apresentadas até agora são muito boas, mas eu também esperava uma ênfase em uma diferença específica entre processamento paralelo e distribuído: o código executado. Considerando os processos paralelos, o código executado é o mesmo, independentemente do nível de paralelismo (instrução, dados, tarefa). Você escreve um único código e ele será executado por diferentes threads / processadores, por exemplo, ao computar produtos de matrizes ou gerar permutações.
Por outro lado, a computação distribuída envolve a execução de diferentes algoritmos / programas ao mesmo tempo em diferentes processadores (de uma ou mais máquinas). Esses cálculos são posteriormente mesclados em resultados intermediários / finais, usando os meios disponíveis de comunicação / sincronização de dados (memória compartilhada, rede). Além disso, a computação distribuída é muito atraente para o processamento do BigData, pois permite explorar o paralelismo do disco (geralmente o gargalo de grandes bancos de dados).
Finalmente, para o nível de paralelismo, pode ser tomado como uma restrição à sincronização. Por exemplo, no GPGPU, que é um dado múltiplo de instrução única (SIMD), o paralelismo ocorre tendo entradas diferentes para uma única instrução, cada par (dado_i, instrução) sendo executado por um encadeamento diferente. Essa é a restrição de que, no caso de ramificações divergentes, é necessário descartar muitos cálculos desnecessários, até que os encadeamentos reconvergam. Para os threads da CPU, porém, eles geralmente divergem; ainda, pode-se usar estruturas de sincronização para conceder execução simultânea de seções específicas do código.