Na prática, há muito pouca diferença: ambos representam unidades de execução separadas cuja interface principal com o mundo externo é via mensagens.
As diferenças estão nos detalhes de implementação dos idiomas. Aqui estão alguns desses detalhes:
- Os canais no Go são digitados; se você quiser enviar mensagens com dados diferentes, precisará de canais separados. Com Erlang, é possível
receive
obter tudo o que é enviado ao processo e deve corresponder aos padrões (no Go, você usaria a select
com vários casos, para que o código parecesse muito semelhante, apenas com canais diferentes).
- Qualquer pessoa pode ler ou escrever um canal Go. Em Erlang, qualquer pessoa pode enviar para um processo, mas somente esse processo será recebido. Isso se torna importante se você deseja dividir uma tarefa entre vários trabalhadores: em Erlang, você precisa criar um processo de distribuição, enquanto o Go pode simplesmente compartilhar um canal.
- Erlang fornece um caminho (principalmente) transparente para a distribuição de processos em vários hosts / VMs. Goroutines estão confinadas a um único processo (embora existam bibliotecas para distribuição).
- O tratamento de erros é muito diferente. Erlang trata cada processo como independente: um erro em um processo (digamos, dividir por 0) não afetará nenhum outro processo, a menos que você os vincule explicitamente (embora algo que esteja aguardando uma mensagem do processo morto seja interrompido). Todas as goroutines são executadas no mesmo espaço de processo; uma divisão por 0 derrubará todo o programa.
- Em Erlang, os dados são imutáveis. Isso significa que toda a comunicação entre um processo e o mundo exterior ocorre por meio de mensagens. Go permite que você compartilhe o estado entre goroutines (embora não deva).
Este último ponto é, penso eu, o mais importante. Embora ambos usem as mensagens como principal meio de comunicação, Erlang oferece garantias muito mais fortes sobre como e quando o estado pode mudar.