El modelo de actor es un modelo matemático de computación paralela , construido alrededor del concepto de actor ( ing. actor "actor; sujeto que actúa"), que se considera una primitiva universal de ejecución paralela. Un actor en este modelo interactúa intercambiando mensajes con otros actores, y cada uno en respuesta a los mensajes recibidos puede tomar decisiones locales, crear nuevos actores, enviar sus propios mensajes y determinar cómo responder a los mensajes posteriores.
Creado como base teórica para una serie de implementaciones prácticas de sistemas paralelos .
Las ideas principales y la base del modelo fueron establecidas en 1973 por la publicación de Hewitt, Bishop y Steiger [1] . Los lenguajes de programación Lisp , Simula y las primeras versiones de Smalltalk , así como los métodos de protección paramétrica y conmutación de paquetes , influyeron en el proceso de formación del modelo . La principal motivación para crear el modelo fue la tarea de construir sistemas informáticos distribuidos basados en cientos y miles de ordenadores independientes equipados con su propia memoria local e interfaces de comunicación [2] . Con la llegada de los sistemas multiprocesador y las arquitecturas multinúcleo , el interés por el modelo actor también aumentó fuera del contexto de los sistemas distribuidos.
En 1975, se desarrolló la semántica operativa para el modelo actor [3] [4] . En 1977, se desarrolló un sistema de leyes axiomáticas para modelos de actores [5] . En 1981 se crea la semántica denotacional del modelo (semántica de las transiciones) [2] [6] , se desarrolla y se generaliza en 1985 [7] ; como resultado de estos trabajos, se reconoce como desarrollada y elaborada la teoría de los modelos actorales.
En la década de 1990, se crearon formalismos que no se corresponden completamente con el modelo actor (no formalizan la entrega garantizada del mensaje), pero son de interés práctico, en particular, varias álgebras de actor diferentes [8] [9] e interpretación basada en lógica lineal. [10] .
Por analogía con la filosofía de la programación orientada a objetos , donde cada primitivo se considera como un objeto, el modelo de actor destaca el concepto de "actor" como una entidad universal. Un actor es una entidad computacional que, en respuesta a un mensaje recibido, puede simultáneamente:
No se supone que haya una secuencia específica de las acciones anteriores y todas se pueden realizar en paralelo.
La separación del remitente de los mensajes enviados fue un logro fundamental del modelo actor: proporciona comunicación asincrónica y control de estructuras en forma de paso de mensajes [11] .
Los destinatarios de los mensajes se identifican mediante una dirección, a veces denominada "dirección postal". Por lo tanto, un actor solo puede interactuar con aquellos actores cuyas direcciones tiene, puede extraer direcciones de los mensajes recibidos o conocerlos de antemano si el actor los creó él mismo.
El modelo se caracteriza por el paralelismo inherente de los cálculos dentro y entre los actores, la creación dinámica de actores, la inclusión de las direcciones de los actores en los mensajes y la interacción solo a través de mensajes asincrónicos directos sin restricciones en el orden de llegada de los mensajes.
El modelo de actor se puede utilizar como base para modelar, comprender y razonar en una amplia gama de sistemas concurrentes , por ejemplo:
Quizás los primeros programas paralelos fueron controladores de interrupciones . Durante el funcionamiento, por regla general, una computadora necesita responder a eventos externos que pueden ocurrir en un momento previamente desconocido (asincrónicamente con respecto al programa que se está ejecutando actualmente), por ejemplo, para recibir información del exterior (caracteres del teclado , paquetes de la red, etc.). El manejo más eficiente de tales eventos se implementa utilizando las llamadas interrupciones. Cuando ocurre un evento, se "interrumpe" la ejecución del programa actual y se inicia el controlador de interrupciones , que realiza las acciones necesarias para responder al evento (por ejemplo, recibe información entrante y la almacena en un búfer, desde donde se puede leer más tarde), después de lo cual el programa principal continúa trabajando desde donde lo dejó .
A principios de la década de 1960, las interrupciones comenzaron a usarse para simular la ejecución simultánea de varios programas en un solo procesador [13] . La presencia de paralelismo con la memoria compartida ha llevado al problema del control de concurrencia. Inicialmente, esta tarea se concibió como uno de los mutex en una computadora separada. Edsger Dijkstra desarrolló semáforos , y más tarde, entre 1971 y 1973, Charles Hoare y Per Hansen desarrollaron monitores [14] [15] [16] para resolver el problema mutex . Sin embargo, ninguna de estas soluciones creó construcciones en lenguajes de programación que encapsularan el acceso a los recursos compartidos. Posteriormente, Hewitt y Atkinson realizaron la encapsulación utilizando construcciones serializadoras ([Hewitt, Atkinson 1977, 1979] y [Atkinson 1980]).
Los primeros modelos de computación (por ejemplo , la máquina de Turing , la máquina de Post , el cálculo lambda, etc.) se basaban en las matemáticas y usaban el concepto de un estado global para definir el "paso de la computación" (posteriormente estos conceptos se generalizaron en los trabajos de McCarthy y Dijkstra [17] [18 ] ). Cada paso computacional pasó de un estado computacional global al siguiente. El enfoque del estado global se ha continuado en la teoría de autómatas para autómatas finitos y máquinas apiladas, incluidas sus versiones no deterministas . Tales autómatas no deterministas tienen la propiedad de no determinismo limitado. Es decir, si la máquina siempre se para antes de pasar al estado inicial, entonces hay un límite en el número de estados en los que puede estar.
Dijkstra desarrolló aún más el enfoque del estado global no determinista. El modelo de Dijkstra ha dado lugar a controversias sobre el no determinismo ilimitado, una propiedad de la computación paralela por la cual la cantidad de latencia en el servicio de una solicitud puede volverse ilimitada como resultado de la competencia de arbitraje por los recursos compartidos, mientras que al mismo tiempo se garantiza que la solicitud finalmente será atendido Hewitt argumentó que el modelo de actor debe brindar garantías para la prestación de un servicio. Aunque en el modelo de Dijkstra no puede haber una cantidad ilimitada de tiempo entre la ejecución de operaciones secuenciales en una computadora, un programa que se ejecuta en paralelo, que comenzó su trabajo en un estado estrictamente definido, solo puede interrumpirse en un número limitado de estados [18]. ] . Por tanto, el modelo de Dijkstra no puede ofrecer garantías para la prestación de un servicio. Dijkstra argumentó que era imposible implementar un no determinismo ilimitado.
Hewitt argumentó lo contrario: no hay límite para el tiempo que se dedica al trabajo de la sección de cálculos, llamada árbitro para resolver conflictos. Los árbitros se ocupan de la resolución de tales situaciones. El reloj de la computadora funciona de forma asíncrona con entradas externas: entrada de teclado, acceso a disco, entrada de red, etc. Por lo tanto, puede llevar una cantidad de tiempo ilimitada recibir un mensaje enviado a una computadora, y en ese tiempo la computadora puede pasar por una cantidad ilimitada de estados.
El no determinismo ilimitado es un rasgo característico del modelo actor, que utiliza el modelo matemático de Klinger basado en la teoría de las regiones [2] . No hay un estado global en el modelo del actor.
Los mensajes en el modelo de actor no necesariamente se almacenan en búfer. Esta es su gran diferencia con los enfoques anteriores del modelo de computación simultánea. La falta de almacenamiento en búfer provocó muchos malentendidos durante el desarrollo del modelo de actor y sigue siendo un tema de controversia hasta el día de hoy. Algunos investigadores argumentan que los mensajes se almacenan en el "aire" o "entorno". Además, los mensajes en el modelo actor simplemente se envían (por ejemplo, paquetes en IP ). No hay ningún requisito para un apretón de manos síncrono con el destinatario.
Una evolución natural del modelo actor fue la capacidad de pasar direcciones en los mensajes. Influenciado por las redes de conmutación de paquetes, Hewitt propuso desarrollar un nuevo modelo de computación concurrente en el que el enlace no tendría ningún campo obligatorio, todos los cuales podrían estar vacíos. Por supuesto, si el remitente del mensaje desea que el destinatario tenga acceso a direcciones que aún no tiene, la dirección debe enviarse en el mensaje.
Durante el cálculo, puede ser necesario enviar un mensaje a un destinatario del que se recibirá una respuesta más tarde. La forma de hacer esto es enviar un mensaje que contenga la dirección de otro actor, llamado currículum (a veces también llamado continuación o pila de llamadas ). El destinatario puede entonces crear un mensaje de respuesta para enviarlo en el currículum .
La creación de actores más la inclusión de las direcciones de los participantes en los mensajes significa que el modelo de actor tiene una topología potencialmente variable en su relación entre sí, similar a los objetos en el lenguaje Simula que también tienen una topología variable en su relación entre sí.
En contraste con el enfoque anterior basado en la combinación de procesos secuenciales, el modelo del actor fue diseñado como un modelo simultáneo en su esencia. Como está escrito en la teoría de modelos de actores, la secuencia en ella es un caso especial que surge de cálculos simultáneos.
Hewitt se opuso a incluir requisitos de que los mensajes deben llegar en el orden en que fueron enviados al modelo actor. Si se desea ordenar los mensajes entrantes, esto se puede modelar con una cola de actores que proporcione esta funcionalidad. Estas colas de actores ordenarían los mensajes entrantes para que se reciban en orden FIFO . En general, si un actor X envía un mensaje M1 a un actor Y , y luego el mismo actor X envía otro mensaje M2 a Y , entonces no se requiere que M1 llegue a Y antes que M2 .
A este respecto, el modelo de actor refleja el sistema de conmutación de paquetes, que no garantiza que los paquetes se reciban en el orden en que se enviaron. La falta de garantías de orden de entrega de mensajes permite que el sistema de conmutación de paquetes almacene paquetes en búfer, use múltiples rutas para enviar paquetes, reenvíe paquetes dañados y use otras técnicas de optimización.
Por ejemplo, los actores pueden usar una canalización de procesamiento de mensajes. Esto significa que en el proceso de procesamiento del mensaje M1 , el actor puede variar el comportamiento que utilizará para procesar el siguiente mensaje. En particular, esto significa que puede comenzar a procesar un mensaje M2 más antes de que se complete el procesamiento de M1 . El hecho de que a un actor se le otorgue el derecho de usar una canalización de procesamiento de mensajes no significa que deba usar esa canalización. Si un mensaje se canalizará o no es una cuestión de compromiso técnico. ¿Cómo puede un observador externo saber que el procesamiento de mensajes de un actor ha pasado por la canalización? No hay ambigüedad sobre el uso de la capacidad de canalización de un actor en este sentido. Solo si, en una implementación particular, la implementación de la optimización canalizada se realiza incorrectamente, puede ocurrir algo diferente al comportamiento esperado.
Otra característica importante del modelo de actor es la localidad: al procesar un mensaje, un actor puede enviar mensajes solo a las direcciones que recibió del mensaje, a las direcciones que ya tenía antes de recibir el mensaje y a las direcciones que creó mientras procesaba el mensaje. mensaje.
La localidad también significa que varios cambios de dirección no pueden ocurrir al mismo tiempo. En este sentido, el modelo de actor difiere de algunos otros modelos de concurrencia, como las redes de Petri , en las que las implementaciones pueden eliminarse simultáneamente desde múltiples posiciones y colocarse en diferentes direcciones.
La idea de componer sistemas de actores en entidades más grandes es un aspecto importante de la modularidad, que se desarrolló en el Ph.D. de Gool Ag .
La principal innovación del modelo de actor fue la introducción del concepto de comportamiento, definido como una función matemática que expresa las acciones de un actor cuando procesa mensajes, incluida la definición de un nuevo comportamiento para procesar el siguiente mensaje entrante. El comportamiento proporciona el funcionamiento del modelo matemático de paralelismo.
El comportamiento también libera al modelo de actor de los detalles de implementación, como en Smalltalk-72, por ejemplo, lo hace el marcador de intérprete de subprocesos. Sin embargo, es importante comprender que la implementación eficiente de los sistemas descritos por el modelo de actor requiere una optimización avanzada.
Otros sistemas de concurrencia (como el cálculo de procesos ) se pueden modelar en el modelo de actor utilizando el protocolo de confirmación de dos fases [19] .
En el modelo del actor, existe un teorema de representación computacional para sistemas cerrados, en el sentido de que no reciben mensajes del exterior. En notación matemática, un sistema cerrado, denotado como S , se construye como la mejor aproximación para el comportamiento inicial, llamado ⊥ S , utilizando una función de comportamiento S de progresión aproximada construida para S de la siguiente manera (según la publicación de Hewitt de 2008):
Denotar S ≡ ⊔ i∈ω progresión S i (⊥ S )Por lo tanto, S se puede caracterizar matemáticamente en términos de todos sus comportamientos posibles (incluido el no determinismo sin restricciones). Aunque Denote S no es una implementación de S , puede usarse para probar la siguiente generalización de la tesis de Church-Turing [20] : si un actor primitivo de un sistema cerrado de actores es eficiente, entonces sus posibles salidas son recursivamente enumerables. La prueba se sigue directamente del teorema de representación computacional.
El desarrollo del modelo actor tiene una interesante conexión con la lógica matemática. Una de las motivaciones clave para su desarrollo fue la necesidad de gestionar aspectos que surgieron durante el desarrollo del lenguaje de programación Planner . Una vez que se formuló originalmente el modelo del actor, se volvió importante determinar el poder del modelo en relación con la tesis de Robert Kowalski de que "los cálculos pueden agruparse mediante inferencias". La tesis de Kowalski resultó ser falsa para cálculos simultáneos en el modelo actor. Este resultado aún es discutible y contradice algunas ideas previas, ya que la tesis de Kowalski es cierta para cálculos secuenciales e incluso para algunos tipos de cálculos paralelos, por ejemplo, para cálculos lambda.
Sin embargo, se han hecho intentos para extender la programación lógica a la computación concurrente. Sin embargo, Hewitt y Aga en un artículo de 1999 argumentan que el sistema resultante no es deductivo en el siguiente sentido: los pasos computacionales de los sistemas de programación lógica paralela no se siguen deductivamente de los pasos anteriores.
La migración en el modelo de actor es la capacidad de un actor para cambiar su ubicación. Por ejemplo, Aki Yonezawa, en su disertación, modeló un servicio postal en el que los actores clientes podían entrar, cambiar de ubicación mientras corrían y salir. Un actor que podía migrar se modeló como un actor con una ubicación específica que cambia cuando el actor migra. Sin embargo, la confiabilidad de esta simulación es controvertida y es objeto de investigación.
Los actores se pueden asegurar de una de las siguientes maneras:
Un punto sutil en el modelo del actor es la capacidad de sintetizar la dirección de un actor. En algunos casos, el sistema de seguridad puede prohibir la síntesis de direcciones. Dado que la dirección de un actor es solo una cadena de bits, obviamente es posible sintetizarla, aunque si la cadena de bits es lo suficientemente larga, es bastante difícil o incluso imposible encontrar la dirección del actor. SOAP utiliza la URL donde se encuentra el actor como la dirección del punto final . Dado que la URL es una cadena de caracteres, obviamente es posible sintetizarla, aunque si se aplica el cifrado, es casi imposible recoger la cadena.
La síntesis de direcciones de actor generalmente se modela con un mapeo. La idea es usar el sistema de actores para mapear las direcciones reales de los actores. Por ejemplo, la estructura de memoria de una computadora se puede modelar como un sistema de actores que proporciona un mapeo. En el caso de las direcciones SOAP , se trata de modelado de DNS y mapeo de URL .
El primer trabajo publicado de Robin Milner sobre concurrencia [21] se destacó por no estar basado en la composición de procesos secuenciales, a diferencia del modelo de actor porque se basaba en un número fijo de procesos, un número fijo de enlaces en la topología de fila utilizada para sincronizar el enlace. El modelo de procesos en serie cooperativos (CSP) original publicado por Anthony Hoare [22] difiere del modelo de actor porque se basa en la composición paralela de un número fijo de procesos secuenciales vinculados en una topología fija y que se comunican mediante el paso de mensajes sincrónicos según el proceso. nombres Las versiones posteriores del CSP se han alejado de la comunicación basada en nombres de procesos, adoptando el principio de comunicación anónima a través de conductos. Este enfoque también se utiliza en el trabajo de Milner sobre el cálculo de los sistemas de comunicación y el cálculo pi .
Ambos modelos tempranos de Milner y Hoare tienen un no determinismo limitado. Los modelos teóricos modernos de sistemas que interactúan [23] proporcionan directamente un no determinismo ilimitado.
Cuarenta años después de la publicación de la Ley de Moore, el continuo aumento en el rendimiento de los chips se debe a los métodos de paralelismo masivo local y global. El paralelismo local se utiliza en nuevos chips para microprocesadores multinúcleo de 64 bits, en módulos multichip y en sistemas de comunicación de alto rendimiento. Actualmente, la simultaneidad global está habilitada en el nuevo hardware de conmutación de paquetes de banda ancha por cable e inalámbrico . La capacidad de almacenamiento debido al paralelismo tanto local como global está creciendo exponencialmente.
El modelo está dirigido a resolver los siguientes problemas de construcción de sistemas informáticos:
Muchas de las ideas introducidas en los modelos de actor ahora también se utilizan en sistemas multiagente por las mismas razones [24] . La diferencia clave es que el agente del sistema (en la mayoría de las definiciones) impone restricciones adicionales a los actores, requiriendo típicamente que usen compromisos y metas.
El modelo de actor también se utiliza en clientes de computación en la nube [25] .
Los primeros lenguajes de programación con soporte para actores incluyen Act 1, 2 y 3 [26] [27] , Acttalk [28] , Ani [29] , Cantor [30] , Rosette [31]
Lenguajes orientados al modelo de actor más recientes: lenguaje concurrente basado en actor (ABCL), ActorScript, AmbientTalk [32] , Axum [33] . Los lenguajes de programación de propósito general que usan el concepto de un actor incluyen E , Elixir [34] , Erlang , Io , SALSA [35] , Scala [36] [37] .
Se han desarrollado bibliotecas y estructuras de tablas con actores para proporcionar un estilo de programación similar al de un actor en lenguajes que no tienen actores integrados.
Bibliotecas y estructuras de mesa con actores. | |||
---|---|---|---|
Nombre | última fecha de lanzamiento | Licencia | Lenguajes de programación |
ActiveJava | 2008 | ? | Java |
Actor | 2013-05-31 | MIT | Java |
Actor-CPP | 2012-03-10 [38] | GPL 2.0 | C++ |
Marco de actores | 2013-11-13 | apache 2.0 | .RED |
ActorKit | 2011-09-13 [39] | BSD | C objetivo |
Akka | 2015-04-23 | apache 2.0 | Java y Scala |
Akka.NET | 2016-01-18 | apache 2.0 | .RED |
Marco de actores de C++ (CAF) | 2015-11-25 [40] | Licencia de software Boost 1.0 y BSD 3-Cláusula | C++11 |
Celuloide | 2016-01-19 [41] | MIT | rubí |
nube haskell | 2015-06-17 [42] | BSD | Haskell |
NubeI | 2015-12-24 [43] | BSD | C/C++, Elixir/Erlang/LFE, Java, Javascript, Perl, PHP, Python, Ruby |
Java funcional | 2016-02-15 [44] | BSD | Java |
Pares G | 2014-05-09 [45] | apache 2.0 | maravilloso |
jetlang | 2013-05-30 [46] | NuevoBSD | Java |
Coro | 2010-02-04 | GPL 3 | Java |
[ 47 ] | 2011-10-13 [48] | MIT | Java |
Estructura del actor de LabVIEW | 2012-03-01 [49] | ? | LabVIEW |
libproceso | 2013-06-19 | apache 2.0 | C++ |
NAact | 2012-02-28 | LGPL 3.0 | .RED |
OSMOS | 2016-02-17 [50] | GPL 2.0 y comercial | C, C++ |
Orbita | 2016-02-16 [51] | NuevoBSD | Java |
Orleáns | 2019-06-04 [52] | MIT | .RED |
Panini | 2014-05-22 | MPL 1.1 | Lenguaje de programación propio |
peernético | 2007-06-29 | LGPL 3.0 | Java |
PostSharp | 2014-09-24 | Comercial / Gratis | .RED |
púlsar | 2016-11-24 [53] | NuevoBSD | Pitón |
púlsar | 2016-02-18 [54] | LGPL / Eclipse | clausura |
pikka | 2022-05-28 [55] | apache 2.0 | Pitón |
React.Net | ? | MIT | .RED |
Retlang | 2011-05-18 [56] | NuevoBSD | .RED |
rotor | 2022-05-23 | MIT | C++17 |
S4 | 2012-07-31 [57] | apache 2.0 | Java |
SObjectizer | 2016-02-11 | NuevoBSD | C++11 |
Esquema de termitas | 2009-05-21 | LGPL | Esquema |
Theron | 2014-01-18 [58] | MIT [59] | C++ |
dramático | 2019-09-11 [60] | Lanzamiento público de GoDaddy [61] | Pitón |
QP | 2015-09-29 [62] | GPL 2.0 y comercial | C y C++ |
Quásar | 2016-01-18 [63] | LGPL / Eclipse | Java |