Je travaille sur la conception d'une application composée de trois parties:
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:
Observer/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 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 traitent 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.
Vous êtes tout près de répondre à votre propre question. :)
Dans le modèle Observable/Observer (notez le flip), il y a trois choses à garder à l'esprit:
En combinant ces points, cela implique que l'observable sait quelles sont ses composantes en aval, c'est-à-dire les observateurs. Le flux de données est intrinsèquement tiré de l'observable - les observateurs ne font que "vivre et mourir" en fonction de ce qu'ils observent.
Dans le modèle Producteur/Consommateur, vous obtenez une interaction très différente:
Le flux de données est maintenant complètement coupé entre un producteur et un consommateur - tout ce que le producteur sait, c'est qu'il a une sortie, et tout ce que le consommateur sait, c'est qu'il a une entrée. Surtout, cela signifie que les producteurs et les consommateurs peuvent exister entièrement sans la présence de l'autre.
Une autre différence pas si subtile est que plusieurs observateurs sur le même observable obtiennent généralement la même charge utile (sauf s'il existe une implémentation non conventionnelle), tandis que plusieurs consommateurs hors même producteur non. Cela dépend si l'intermédiaire est une approche de type file d'attente ou sujet. Le premier transmet un message différent pour chaque consommateur, tandis que le second garantit (ou tente) que tous les consommateurs traitent message par message.
Pour les adapter à votre application:
Par conséquent, pour répondre directement à votre question: si vous souhaitez maintenir un certain niveau de séparation entre votre fil de visionnage et votre contrôleur de sorte que vous puissiez les faire fonctionner indépendamment, vous devez tendre vers le modèle Producteur/Consommateur.