L'expérience Cosmic Cube reposait sur le principe que la communication inter-nœuds devait être facilement extensible à un très grand nombre de nœuds. Un réseau direct comme l'hypercube répond à cette exigence, tant en termes de bande passante agrégée atteinte grâce aux nombreux canaux de communication simultanés que de faisabilité de la mise en œuvre. L' hypercube est en réalité une variante distribuée d'un réseau à commutation logarithmique indirecte , tel que les réseaux Omega ou Banyan : dans les organisations à stockage partagé, on utilise généralement des chemins de communication uniformes. Cependant, avec l'architecture de l'hypercube, les chemins de communication peuvent emprunter un nombre variable de canaux, ce qui engendre des latences différentes. Il est ainsi possible d'optimiser les performances en plaçant les processus sur les nœuds en fonction de la localité de communication.
Machine J
La J-Machine a été développée par Bill Dally et al. au MIT et offre un support architectural adapté aux acteurs. Ce support comprend notamment les éléments suivants :
- Messagerie asynchrone
- Un espace uniforme d'adresses d'acteurs auquel des messages peuvent être envoyés simultanément, que l'acteur destinataire soit local ou non.
- Une forme de filière d'acteurs (voir modèle d'acteur )
Smalltalk concurrent (qui peut être modélisé à l'aide d'acteurs ) a été développé pour programmer la machine J.
Langage de programmation d'acteurs prototype
Hewitt [2006] a présenté un prototype de langage de programmation d'acteurs , en ce sens qu'il exprime directement des aspects importants du comportement des acteurs. Les messages sont exprimés en XML à l'aide de la notation suivante : :<tag>[<element>1 ... <element>] for
- “<”<tag>“>” <element>1 ... <element>n “<”/<tag>“>”
La sémantique du langage de programmation est définie en représentant chaque élément du programme comme un acteur doté de son propre comportement. L'exécution est modélisée par l'échange de messages Eval entre ces éléments lors de l'exécution.
acteurs environnementaux
Chaque Evalmessage contient l'adresse d'un acteur qui représente un environnement, associé à des identifiants de programme. Les acteurs d'environnement sont immuables ; ils ne changent pas. Lorsqu'un Request[Bind[identifier value] customer]acteur d'environnement reçoit un message, un nouvel acteur d'environnement est créé. Si ce nouvel acteur reçoit un message, il envoie un autre message Request[Lookup[identifier’] customer’]si le message identifierest identique au identifier’message reçu customer’Returned[value], sinon il envoie un autre message Environment Request[Lookup[identifier’] customer’]. Ce mécanisme repose sur un acteur EmptyEnvironmentqui, lorsqu'il reçoit un message Request[Lookup[identifier] customer], envoie un autre message . Lorsqu'il reçoit une requête, il agit de la même manière .customerThrown[NotFound[identifier]]BindEmptyEnvironmentEnvironment
Expressions
Le langage de programmation prototype comporte des expressions des types suivants :
- < identifier >
- Dès Request[Eval[environment] customer]réception, envoyezenvironmentRequest[Lookup[<identifier>] customer]
- envoyer < destinataire > < communication >
- Lorsque Request[Eval[environment] customer]vous recevez ceci, envoyez " où est un nouvel acteur tel que"<recipient>Request[Eval[environment] evalCustomer1]evalCustomer1
- lorsqu'il reçoit la communication , alors envoyerevalCustomer1Returned[theRecipient]<communication>
- Request[Eval[environment] evalCustomer2]où se trouve un nouvel acteur tel queevalCustomer2
- lorsqu'il reçoit la communication , alors envoyez-la .evalCustomer2Returned[theCommunication]theRecipienttheCommunication
- < destinataire > . < message >
- Dès Request[Eval[environment] customer]réception, envoyez de sorte que<recipient>Request[Eval[environment] evalCustomer1]
- lorsqu'il reçoit la communication , alors envoyez de sorte queevalCustomer1Returned[theRecipient]<message>Request[Eval[environment] evalCustomer2]
- lorsqu'il reçoit la communication , alors envoyerevalCustomer2Returned[theMessage]theRecipient
- Request[theMessage customer]
- récepteur ... < motif > i < expression > i ...
- Dès Request[Eval[environment] customer]réception, envoyez customerun nouvel acteur theReceivertel que
- lorsqu'il theReceiverreçoit une communication com, créez un nouvel bindingCustomerenvironnement d'envoi.
- Request[Bind[<pattern>i com] bindingCustomer]et
- si bindingCustomerreçoit Returned[environment’], envoyer<expression>i
- Request[Eval[environment’]]
- sinon, si bindingCustomerreçoit Thrown[...], essayez<pattern>i+1
- comportement ... < motif > i < expression > i ...
- Dès Request[Eval[environment] customer]réception, envoyez au client un nouvel acteur theReceivertel que
- lorsqu'il theReceiverreçoit Request[message customer’], alors créez-en un nouveau bindingCustomeret envoyez-leenvironment
- Request[bind[<pattern>i message] customer’]et
- si bindingCustomerreçoit Returned[environment’], envoyer<expression>i
- Request[Eval[environment’] customer’]
- sinon, si bindingCustomerreçoit Thrown[...], essayez<pattern>i+1
- si bindingCustomerreçoit Returned[environment’], envoyer<expression>i
- { < expression > 1 , < expression > 2 }
- Lorsqu'il Request[Eval[environment] customer]est reçu, envoyez-le et envoyez simultanément .<expression>1Request[Eval[environment]]<expression>2Request[Eval[environment]] customer]
- soit < identifier > = < expression > valeur dans < expression > corps
- Une fois message[Eval[environment] customer]reçu, créez-en un nouveau evalCustomeret envoyez-le.<expression>value
- Request[Eval[environment] evalCustomer1.
- Lorsqu'il evalCustomerreçoit Returned[theValue], créez-en un nouveau bindingCustomeret envoyez-leenvironment
- Request[bind[<identifier> theValue] bindingCustomer]
- Lorsque bindingCustomerreçoit Returned[environment’], envoyer<expression>bodyRequest[Eval[environment’] customer]
- sérialiseur < expression >
- Lorsqu'il Request[Eval[environment] customer]est reçu, envoyez-le à customerReturned[theSerializer]l'endroit où theSerializerse trouve un nouvel acteur tel que les communications envoyées à theSerializersoient traitées dans l'ordre FIFO avec un acteur de comportement qui est initialement et<expression>.Eval[environment]
- Lorsque la communication comest reçue par theSerializer, alors envoyez l'acteur de comportement Request[com customer’]où customer’est un nouvel acteur tel que
- lorsque customer’reçoit Returned[theNextBehavior]alors theNextBehaviorest utilisé comme acteur de comportement pour la prochaine communication reçue par theSerializer.
Exemple de programme
Voici un exemple de programme pour une cellule de stockage simple pouvant contenir n'importe quelle adresse d'acteur :
- Cellule ≡
- récepteur
- Demande[Créer[client initial]]
- envoyer client Retourné[ sérialiseur ReadWrite(initial)]
- Demande[Créer[client initial]]
- récepteur
Le programme ci-dessus, qui crée une cellule de stockage, utilise le comportement ReadWrite défini comme suit :
- LireÉcrire(contenu) ≡
- comportement
- Demande[lire[] client]
- { envoyer client Returned[contents], ReadWrite(contents)}
- Demande[écrire[x] client]
- { envoyer client Returned[], ReadWrite(x)}
- Demande[lire[] client]
- comportement
Le comportement décrit ci-dessus est encapsulé, c'est-à-dire que le traitement d'un message de lecture ou d'écriture précédent peut se poursuivre pendant le traitement d'un message de lecture ou d'écriture suivant. Par exemple, l'expression suivante crée une cellule x avec le contenu initial 5, puis y écrit simultanément les valeurs 7 et 9.
- soit x = Cell.Create[5] dans {x.write[7], x.write[9], x.read[]}
La valeur de l'expression ci-dessus est 5, 7 ou 9.