DEV Community

Cover image for Actor Model, modelo do ator em programação! Você conhece?
Uriel dos Santos Souza
Uriel dos Santos Souza

Posted on • Updated on

Actor Model, modelo do ator em programação! Você conhece?

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

Top comments (2)

Collapse
 
geazi_anc profile image
Geazi Anc

Muito bom, uma explicação bem simples e didática.

Collapse
 
eduardoklosowski profile image
Eduardo Klosowski

Gostei do artigo e é sempre bom conhecer essas estratégias para ter como opção a ser considerada quando um problema que pode ser resolvido com ela aparecer.