Je travaille sur la conception d'une application composée de trois parties:
- un seul thread qui surveille certains événements qui se produisent (création de fichiers, demandes externes, etc.)
- N threads de travail qui répondent à ces événements en les traitant (chaque travailleur traite et consomme un seul événement et le traitement peut prendre un temps variable)
- un contrôleur qui gère ces threads et gère les erreurs (redémarrage des threads, journalisation des résultats)
Bien que ce soit assez basique et pas difficile à implémenter, je me demande quelle serait la "bonne" façon de le faire (dans ce cas concret en Java, mais des réponses d'abstraction plus élevées sont également appréciées). Deux stratégies me viennent à l'esprit:
Observateur / Observable: le fil d'observation est observé par le contrôleur. En cas d'événement, le contrôleur est alors notifié et peut affecter la nouvelle tâche à un thread libre à partir d'un pool de threads mis en cache réutilisable (ou attendre et mettre en cache les tâches dans la file d'attente FIFO si tous les threads sont actuellement occupés). Les threads de travail implémentent Callable et retournent avec succès le résultat (ou une valeur booléenne), ou retournent avec une erreur, auquel cas le contrôleur peut décider quoi faire (selon la nature de l'erreur qui s'est produite).
Producteur / consommateur : le thread de surveillance partage une BlockingQueue avec le contrôleur (file d'attente d'événements) et le contrôleur en partage deux avec tous les travailleurs (file d'attente des tâches et file d'attente des résultats). En cas d'événement, le thread de surveillance place un objet de tâche dans la file d'attente des événements. Le contrôleur prend de nouvelles tâches dans la file d'attente des événements, les examine et les place dans la file d'attente des tâches. Chaque travailleur attend de nouvelles tâches et les prend / les consomme dans la file d'attente des tâches (premier arrivé, premier servi, géré par la file d'attente elle-même), remettant les résultats ou les erreurs dans la file d'attente des résultats. Enfin, le contrôleur peut récupérer les résultats de la file d'attente de résultats et prendre les mesures appropriées en cas d'erreurs.
Les résultats finaux des deux approches sont similaires, mais ils présentent chacun de légères différences:
Avec Observers, le contrôle des threads est direct et chaque tâche est attribuée à un nouveau travailleur spécifique. Les frais généraux pour la création de threads peuvent être plus élevés, mais pas beaucoup grâce au pool de threads mis en cache. En revanche, le modèle Observer est réduit à un seul Observateur au lieu de plusieurs, ce qui n'est pas exactement ce pour quoi il a été conçu.
La stratégie de file d'attente semble être plus facile à étendre, par exemple, l'ajout de plusieurs producteurs au lieu d'un est simple et ne nécessite aucune modification. L'inconvénient est que tous les threads s'exécuteraient indéfiniment, même lorsqu'ils ne font aucun travail, et la gestion des erreurs / résultats ne semble pas aussi élégante que dans la première solution.
Quelle serait l'approche la plus appropriée dans cette situation et pourquoi? J'ai trouvé difficile de trouver des réponses à cette question en ligne, car la plupart des exemples ne concernent que des cas clairs, comme la mise à jour de nombreuses fenêtres avec une nouvelle valeur dans le cas Observer ou le traitement avec plusieurs consommateurs et producteurs. Toute contribution est grandement appréciée.