2009-05-28 5 views
8

Je tir hors tâches à l'aide d'un ExecutorService, les tâches de répartition qui doivent être regroupés selon des critères spécifiques à la tâche:Comment suivre les statistiques d'exécution de tâches à l'aide d'un ExecutorService?

Task[type=a] 
Task[type=b] 
Task[type=a] 
... 

périodiquement Je veux sortir la durée moyenne du temps que chaque tâche a (regroupées par type) avec des informations statistiques telles que la moyenne/médiane et l'écart-type.

Cela doit être assez rapide, bien sûr, et idéalement ne devrait pas provoquer la synchronisation des différents threads lorsqu'ils rapportent des statistiques. Qu'est-ce qu'une bonne architecture pour faire ça?

+0

Je devrais noter; Je sais où je vais appeler ces méthodes, je voudrais savoir ce que je devrais utiliser pour accumuler les données. –

+0

Est-ce que chaque type de tâche a son propre Runnable? – Gandalf

+0

Oui, ils le font. Des trucs basiques, bien sûr, mais il y a quelques informations stockées dans la tâche avant de l'envoyer. –

Répondre

9

ThreadPoolExecutor fournit les méthodes beforeExecute et afterExecute que vous pouvez remplacer. Vous pouvez les utiliser pour enregistrer vos statistiques dans une seule (variable membre de votre ExecutorService) ConcurrentHashMap en utilisant un identifiant unique pour vos tâches et en stockant le type, l'heure de début et l'heure de fin.

Calculez les statistiques à partir du ConcurrentHashMap lorsque vous êtes prêt à les consulter.

4

Sous Thread Pool Executor et de suivre les événements d'exécution:

Il convient de noter que les méthodes sont invoquées par le thread de travail qui exécute la tâche, Vous devez donc assurer la sécurité des threads pour le code de suivi d'exécution. De même, les fichiers exécutables que vous recevrez ne seront probablement pas vos fichiers exécutables, mais enveloppés dans les futures commandes.

+1

Votre dernier point est très important. J'ai eu la même question pour Callables soumis à un ThreadPoolExecutor. Malheureusement, le Runnable qui arrive dans beforeExecute est une FutureTask enveloppant mon Callable (et il semblerait que la même chose soit vraie pour un Runnable soumis). Par conséquent, il n'existe aucun moyen facile d'accéder à votre Runnable/Callable original. Décevante ... :(On dirait que je vais surcharger submit() aussi pour garder une carte de Future à Callable J'espère que ça ne ralentit pas trop les choses. –

1

Je crois que les deux autres réponses sont correctes, mais peut-être un peu trop compliqué (même si ma réponse, bien que simple, est sans doute pas tout à fait aussi performant que le leur.

Pourquoi ne pas simplement utiliser des variables atomiques de garder une trace de Vos statistiques, telles que le nombre de tâches exécutées, le temps total d'exécution (divisé par le nombre total, vous obtenez un temps d'exécution moyen) .Passez ces variables dans votre Runnable pour chaque tâche. le verrouillage d'une variable Atomic aura un impact sur vous

2

Une autre méthode consiste à utiliser un modèle wrapper/decorator

public class Job implements Runnable { 
private Runnable _task; 
private Statistics _statistics; 

public Job(Runnable task, Statistics statistics) { 
    this._task = task; 
} 

public void run() { 
    long s = System.currentTimeMillis(); 
    _task.run(); 
    long e = System.currentTimeMillis(); 

    long executionTime = e - s; 
    _statistics.updateStatistics(executionTime); 
} 
} 
Questions connexes