2024-05-04 02:08:18
Les classes d’acteurs vous permettent de créer des réseaux d’acteurs par programmation. Les classes d’acteurs doivent être définies dans un fichier source distinct. Pour illustrer comment définir et importer des classes d’acteurs, l’exemple suivant implémente un mappage distribué de clés de type Nat vers des valeurs de type Text. Il fournit des fonctions simples d’insertion et de recherche, put(k, v) et get(k), pour travailler avec ces clés et valeurs.
Pour distribuer les données de cet exemple, l’ensemble de clés est partitionné en n compartiments. Pour l’instant, fixons simplement n = 8. Le compartiment, i, d’une clé, k, est déterminé par le reste de k divisé par n, c’est-à-dire i = k % n. Le ième seau (je suis dans [0..n)) receives a dedicated actor to store text values assigned to keys in that bucket.
The actor responsible for bucket i is obtained as an instance of the actor class Bucket(i), defined in the sample Buckets.mo file, as follows:
Buckets.mo:
import Nat “mo:base/Nat”;
import Map “mo:base/RBTree”;
actor class Bucket(n : Nat, i : Nat) {
type Key = Nat;
type Value = Text;
let map = Map.RBTree
public func get(k : Key) : async ?Value {
assert((k % n) == i);
map.get(k);
};
public func put(k : Key, v : Value) : async () {
assert((k % n) == i);
map.put(k,v);
};
};
A bucket stores the current mapping of keys to values in a mutable map variable containing an imperative RedBlack tree, map, that is initially empty.
On get(k), the bucket actor simply returns any value stored at k, returning map.get(k).
On put(k, v), the bucket actor updates the current map to map k to ?v by calling map.put(k, v).
Both functions use the class parameters n and i to verify that the key is appropriate for the bucket by asserting ((k % n) == i).
Clients of the map can then communicate with a coordinating Map actor, implemented as follows:
import Array “mo:base/Array”;
import Buckets “Buckets”;
actor Map {
let n = 8;
type Key = Nat;
type Value = Text;
type Bucket = Buckets.Bucket;
let buckets : [var ?Bucket] = Array.init(n, nul);
public func get(k : Key) : async ?Value {
interrupteur (seaux[k % n]) {
cas nul nul ;
cas (?bucket) wait bucket.get(k);
} ;
} ;
public func put(k : Clé, v : Valeur) : async () {
soit je = k % n ;
laisser seau = changer (seaux[i]) {
cas nul {
soit b = attendre Buckets.Bucket(n, i);
seaux[i] := ?b;
b;
} ;
seau de caisse (? seau);
} ;
attendre bucket.put(k, v);
} ;
} ;
Comme cet exemple l’illustre, le code Map importe la classe d’acteur Bucket en tant que module Buckets.
L’acteur gère un tableau de n compartiments alloués, avec toutes les entrées initialement nulles. Les entrées sont remplies avec des acteurs Bucket à la demande.
Sur get(k, v), l’acteur Map :
Utilise le reste de la clé k divisé par n pour déterminer l’index i du compartiment responsable de cette clé.
Renvoie null si le ième compartiment n’existe pas, ou
Déléguez à ce compartiment en appelant bucket.get(k, v) si c’est le cas.
Sur put(k, v), l’acteur Map :
Utilise le reste de la clé k divisé par n pour déterminer l’index i du compartiment responsable de cette clé.
Installe le compartiment i si le compartiment n’existe pas à l’aide d’un appel asynchrone au constructeur, Buckets.Bucket(i), et, après avoir attendu le résultat, l’enregistre dans les compartiments du tableau.
Délégue l’insertion à ce compartiment en appelant bucket.put(k, v).
Bien que cet exemple fixe le nombre de compartiments à 8, vous pouvez généraliser l’exemple en faisant de l’acteur Map une classe d’acteur, en ajoutant un paramètre (n : Nat) et en omettant la déclaration let n = 8;.
Par exemple:
classe d’acteur Map(n : Nat) {
tapez Clé = Nat
…
}
Les clients de la classe d’acteur Map sont désormais libres de déterminer le nombre maximum de buckets dans le réseau en passant un argument de construction.
Sur ICP, les appels à un constructeur de classe doivent être dotés de cycles pour payer la création d’un principal. Voir ExperimentalCycles pour obtenir des instructions sur la façon d’ajouter des cycles à un appel en utilisant l’impératif ExperimentalCycles.add
Sur ICP, le constructeur principal d’une classe d’acteur importée crée toujours un nouveau principal et installe une nouvelle instance de la classe comme code pour ce principal.
Pour fournir un contrôle supplémentaire sur l’installation des classes d’acteurs, Motoko dote chaque classe d’acteurs importée d’un constructeur secondaire supplémentaire. Ce constructeur prend un premier argument supplémentaire qui spécifie le mode d’installation souhaité. Le constructeur n’est disponible que via une syntaxe spéciale qui met l’accent sur sa fonctionnalité système.
En utilisant cette syntaxe, il est possible de spécifier les paramètres initiaux des cartouches (tels qu’un ensemble de contrôleurs), d’installer, de mettre à niveau et de réinstaller manuellement les cartouches, exposant ainsi toutes les fonctionnalités de niveau inférieur de l’ordinateur Internet.
Voir gestion des classes d’acteurs pour plus de détails.
#Cours #dacteur #Ordinateur #Internet
1714785357