Le Active Object Pattern est un modèle de conception de concurrence qui dissocie l'exécution de méthode de l'invocation de méthode. L'objectif principal de ce modèle est d'introduire un comportement asynchrone en exécutant des opérations dans un thread séparé, tout en fournissant une interface synchrone au client. Ceci est réalisé en utilisant une combinaison de transmission de messages, de files d'attente de requêtes et de mécanismes de planification.
Disons que nous devons faire un calcul, peut-être un appel API, une requête de base de données, etc. Je ne vais implémenter aucune gestion des exceptions car je suis trop paresseux.
def compute(x, y): time.sleep(2) # Some time taking task return x + y
Vous trouverez ci-dessous un exemple de la façon dont nous pourrions gérer les requêtes simultanées sans utiliser le modèle d'objet actif.
import threading import time def main(): # Start threads directly results = {} def worker(task_id, x, y): results[task_id] = compute(x, y) print("Submitting tasks...") thread1 = threading.Thread(target=worker, args=(1, 5, 10)) thread2 = threading.Thread(target=worker, args=(2, 15, 20)) thread1.start() thread2.start() print("Doing other work...") thread1.join() thread2.join() # Retrieve results print("Result 1:", results[1]) print("Result 2:", results[2]) if __name__ == "__main__": main()
Gestion des threads : La gestion directe des threads augmente la complexité, d'autant plus que le nombre de tâches augmente.
Manque d'abstraction : Le client est responsable de la gestion du cycle de vie des threads, en couplant la gestion des tâches avec la logique métier.
Problèmes d'évolutivité : Sans une file d'attente ou un mécanisme de planification approprié, il n'y a aucun contrôle sur l'ordre d'exécution des tâches.
Réactivité limitée : Le client doit attendre que les discussions se rejoignent avant d'accéder aux résultats.
Vous trouverez ci-dessous une implémentation Python du modèle d'objet actif utilisant des threads et des files d'attente pour faire la même chose que ci-dessus. Nous allons parcourir chaque partie une par une :
MethodRequest : Encapsule la méthode, les arguments et un Future pour stocker le résultat.
def compute(x, y): time.sleep(2) # Some time taking task return x + y
Planificateur : traite en continu les requêtes de la file d'attente d'activation dans un fil de discussion séparé.
import threading import time def main(): # Start threads directly results = {} def worker(task_id, x, y): results[task_id] = compute(x, y) print("Submitting tasks...") thread1 = threading.Thread(target=worker, args=(1, 5, 10)) thread2 = threading.Thread(target=worker, args=(2, 15, 20)) thread1.start() thread2.start() print("Doing other work...") thread1.join() thread2.join() # Retrieve results print("Result 1:", results[1]) print("Result 2:", results[2]) if __name__ == "__main__": main()
Servant : implémente la logique réelle (par exemple, la méthode de calcul).
class MethodRequest: def __init__(self, method, args, kwargs, future): self.method = method self.args = args self.kwargs = kwargs self.future = future def execute(self): try: result = self.method(*self.args, **self.kwargs) self.future.set_result(result) except Exception as e: self.future.set_exception(e)
Proxy : Traduit les appels de méthode en requêtes et renvoie un Future pour le résultat.
import threading import queue class Scheduler(threading.Thread): def __init__(self): super().__init__() self.activation_queue = queue.Queue() self._stop_event = threading.Event() def enqueue(self, request): self.activation_queue.put(request) def run(self): while not self._stop_event.is_set(): try: request = self.activation_queue.get(timeout=0.1) request.execute() except queue.Empty: continue def stop(self): self._stop_event.set() self.join()
Client : soumet les tâches de manière asynchrone et récupère les résultats en cas de besoin.
import time class Servant: def compute(self, x, y): time.sleep(2) return x + y
L'Active Object Pattern est un outil puissant pour gérer les opérations asynchrones dans des environnements multithread. En séparant l'invocation de méthode de l'exécution, il garantit une meilleure réactivité, une évolutivité et une base de code plus propre. Bien qu'il présente une certaine complexité et une surcharge potentielle en termes de performances, ses avantages en font un excellent choix pour les scénarios nécessitant une concurrence élevée et une exécution prévisible. Cependant, son utilisation dépend du problème spécifique à résoudre. Comme pour la plupart des modèles et algorithmes, il n’existe pas de solution universelle.
Wikipédia - Objet actif
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!