Actor Model, modelo do ator em programação! Você conhece?
Tags: braziliandevs, actor, programming
Published: 2023-06-20 16:18:57

O Actor Model é um modelo matemático para sistemas concorrentes em ciência da computação. Ou em outras palavras: o modelo de ator fornece regras e primitivas para lidar com o **paralelismo**. 

Actor Model é um modelo conceitual de computação concorrente, **surgiu em 1973**.

As regras, que normalmente são impostas pela linguagem ERLANG, são as seguintes:

- Tudo (não primitivo) é um ator
- Um ator tem estado local (“variáveis”)
- Um ator é uma entidade computacional (“processo”) que executa sequencialmente (“single-threaded”)
- Um ator tem um endereço (no sentido de caixa de correio, não de memória)
- Um ator pode receber mensagens e reagir a elas por:
  - Mutando seu estado local
  - Criando novos atores
  - Envio de mensagens para outros atores de forma assíncrona usando seus endereços

Embora cada ator seja executado sequencialmente, ou seja, apenas uma mensagem é processada por um ator por vez, dois atores podem muito bem ser executados em paralelo.

As implementações mais famosas para o Actor Model são Akka & Erlang. Falaramos mais de Erlang. 

Os atores são leves e é muito fácil criar milhões deles, pois consomem menos recursos do que os Threads. 

> O estado privado do ator só pode ser alterado pelo processamento de uma mensagem, ele pode manipular apenas uma mensagem por vez e eles funcionam de forma assíncrona, isso significa que um ator nunca espera por uma resposta de outro ator.

No cenário distribuído, é possível que os Atores estejam em máquinas diferentes, portanto, eles se comunicam com endereços com mensagens, um endereço pode ser um endereço local ou um endereço remoto.

A linguagem Erlang, construída por Joe Armstrong na Ericson, ainda é usada hoje para sistemas extremamente escaláveis e tolerantes a falhas. 

Por exemplo, os backbones de sua conexão LTE são escritos em Erlang e também são usados para produtos como WhatsApp ou usados ​​por empresas como Facebook e Amazon.

Actor Model não precisa de nenhuma primitiva de sincronização como mutexes ou semáforos. Nenhum ator pode modificar o estado local de outro ator e cada ator em si é **single-threaded. **

Qualquer recurso exigido por vários atores deve ter seu próprio ator designado que gerencia o acesso a esse recurso. Todos os outros atores podem solicitar operações a serem executadas enviando uma mensagem ao ator gestor.

> "Um ator é a unidade primitiva de computação. É aquilo que recebe uma mensagem e faz algum tipo de cálculo com base nela."  
Basicamente como Alan Kays definia OOP. 

A ideia é muito parecida com a que temos nas linguagens orientadas a objetos: um objeto recebe uma mensagem (uma chamada de método) e faz algo dependendo de qual mensagem ele recebe (qual método estamos chamando).



A principal diferença é que os **atores estão completamente isolados **uns dos outros e **nunca compartilharão a memória**. Também vale a pena notar que um ator pode manter um estado privado que nunca pode ser alterado diretamente por outro ator.

Uma diferença importante entre passar mensagens e chamar métodos é que as mensagens não têm valor de retorno. Ao enviar uma mensagem, um ator delega trabalho a outro ator, se esperasse um valor de retorno, o ator remetente precisaria bloquear ou executar o trabalho do outro ator no mesmo thread. Em vez disso, o ator receptor entrega os resultados em uma mensagem de resposta.

Os atores reagem às mensagens da mesma forma que os objetos “reagem” aos métodos invocados neles. A diferença é que, em vez de vários encadeamentos “projetando” em nosso ator e causando estragos no estado interno e invariantes, os atores executam independentemente dos remetentes de uma mensagem e reagem às mensagens recebidas sequencialmente, uma de cada vez. Enquanto cada ator processa as mensagens enviadas a ele sequencialmente, diferentes atores trabalham simultaneamente uns com os outros para que um sistema de ator possa processar tantas mensagens simultaneamente quantas o hardware suportar.


> No modelo de ator tudo é um ator e eles precisam ter endereços para que um ator possa enviar uma mensagem para outro.
 
Atores têm **caixas de correio**
É importante entender que, embora vários atores possam ser executados ao mesmo tempo, um ator processará uma determinada mensagem sequencialmente. **Isso significa que se você enviar 3 mensagens para o mesmo ator, ele executará apenas uma de cada vez**. Para que essas 3 mensagens sejam executadas simultaneamente, você precisa criar 3 atores e enviar uma mensagem para cada um.

As mensagens são enviadas de forma assíncrona para um ator, que precisa armazená-las em algum lugar enquanto processa outra mensagem. **A caixa de correio é o local onde essas mensagens são armazenadas**.

Os atores se comunicam entre si enviando mensagens assíncronas. Essas mensagens são armazenadas nas caixas de correio de outros atores até serem processadas.

O uso de passagem de mensagens evita travamentos e bloqueios.

Em vez de chamar métodos(oop), os atores enviam mensagens uns aos outros. O envio de uma mensagem não transfere o thread de execução do remetente para o destino. Um ator pode enviar uma mensagem e continuar sem bloquear. Portanto, ele pode realizar mais na mesma quantidade de tempo.


O que os atores fazem
Quando um ator recebe uma mensagem, ele pode fazer uma destas 3 coisas:

- Criar mais atores
- Enviar mensagens para outros atores
- Designar o que fazer com a próxima mensagem

Um ator pode manter um estado privado. 

> “Designar o que fazer com a próxima mensagem” 

significa basicamente definir como será esse estado para a próxima mensagem que receber. Ou, mais claramente, é como os atores mudam de estado.

Vamos imaginar que temos um ator que se comporta como uma calculadora e que seu estado inicial é simplesmente o número 0. Quando este ator recebe a mensagem add(1), ao invés de mudar seu estado original, ele designa que para a próxima mensagem que receber, o estado será 1.

### Tolerância a erro

Erlang introduziu a filosofia **“deixe travar”. **A ideia é que você não precise programar defensivamente, tentando antecipar todos os possíveis problemas que podem acontecer e encontrar uma maneira de lidar com eles, **simplesmente porque não há como pensar em cada ponto de falha.**

O que Erlang faz é simplesmente deixá-lo travar, mas fazer com que esse código crítico seja supervisionado por alguém cuja única responsabilidade seja saber o que fazer quando esse travamento acontecer(como redefinir essa unidade de código para um estado estável), e o que torna tudo isso possível é o modelo de ator.

Todo código roda dentro de um process(é basicamente assim que Erlang chama seus atores). 
Isse process é completamente isolado, o que significa que seu estado não influenciará nenhum outro process. Temos um supervisor, que é basicamente outro process(tudo é ator, lembra?), que será avisado quando o supervisionado process travar e poderá fazer algo a respeito.

Isso possibilita a criação de sistemas que se **“autocuram”**, o que significa que se um ator chegar a um estado excepcional e travar, por qualquer motivo, um supervisor pode fazer algo a respeito para tentar colocá-lo em um estado consistente novamente (e há existem várias estratégias para fazer isso, sendo a mais comum apenas reiniciar o ator com seu estado inicial).

Distribuição

Outro aspecto interessante do modelo de ator é que **não importa se o ator para o qual estou enviando uma mensagem está sendo executado localmente ou em outro nó.**

Pense nisso, se um ator é apenas esta unidade de código com uma caixa de correio e um estado interno, e apenas responde a mensagens, quem se importa em qual máquina ele está realmente rodando? Contanto que possamos fazer a mensagem chegar lá, estamos bem.

Isso nos permite criar sistemas que aproveitam vários computadores e nos ajudam a recuperar se um deles falhar.

### Prós do modelo de ator
- Fácil de escalar
- Tolerante a falhas
- Nenhum estado compartilhado

### Contras do modelo de ator
- A caixa de correio pode transbordar
- Suscetível a impasses

O Actor Model é bem conceituado e faz todo o sentido usar o Actor Model se alguém estiver projetando sistemas concorrentes. 


Fontes: 
https://surma.dev/things/actormodel/
https://www.brianstorti.com/the-actor-model/
https://en.wikipedia.org/wiki/Actor_model
https://eximia.co/reactive-messaging-patterns-with-the-actor-model/
https://medium.com/@KtheAgent/actor-model-in-nutshell-d13c0f81c8c7
https://doc.akka.io/docs/akka/current/typed/guide/actors-intro.html
https://getakka.net/articles/intro/what-are-actors.html
https://s3-sa-east-1.amazonaws.com/thedevconf/presentations/TDC2019SP/dotnet/UJJ-3987_2019-07-17T025204_Introdu%C3%A7%C3%A3o%20ao%20Actor%20Model%20com%20Microsoft%20Orleans.pdf