2009-05-28 18 views
8

estoy disparando tareas utilizando un ExecutorService, el envío de tareas que deben ser agrupados por criterios específicos de la tarea:¿Cómo rastrear las estadísticas de ejecución de tareas usando un ExecutorService?

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

Periódicamente me quieren dar salida a la duración media de tiempo que tomó cada tarea (agrupados por type) junto con información estadística como media/mediana y desviación estándar.

Esto debe ser bastante rápido, por supuesto, e idealmente no debería causar que los distintos subprocesos se sincronicen cuando informan las estadísticas. ¿Cuál es una buena arquitectura para hacer esto?

+0

Debo notar; Sé de dónde voy a llamar a estos métodos, me gustaría recibir consejos sobre qué debería usar para acumular los datos. –

+0

¿Cada tipo de tarea tiene su propio ejecutable? – Gandalf

+0

Sí, lo hacen. Bastante básico, por supuesto, pero hay algo de información almacenada en la tarea antes de enviarla. –

Respuesta

9

ThreadPoolExecutor proporciona beforeExecute y afterExecute métodos que puede anular. Puede utilizarlos para registrar sus estadísticas en una sola (variable miembro de su ExecutorService) ConcurrentHashMap codificada en algún identificador único para sus tareas, y almacenar el tipo, la hora de inicio y la hora de finalización.

Calcula las estadísticas del ConcurrentHashMap cuando estés listo para verlas.

4

Subclase Thread Pool Executor y realizar un seguimiento de los eventos de ejecución:

Vale la pena señalar que los métodos son invocados por el subproceso de trabajo que ejecuta la tarea, por lo que debe asegurar la seguridad del hilo para el código de seguimiento de la ejecución.

Además, los Runnables que recibirá probablemente no sean sus Runnables, sino que se incluirán en FutureTasks.

+1

Su último punto es muy importante. Tenía la misma pregunta para Callables enviada a un ThreadPoolExecutor. Desafortunadamente, el Runnable que entra en beforeExecute es un FutureTask que envuelve my Callable (y parece que lo mismo sería cierto para un Runnable enviado). Como resultado, no hay una manera fácil de acceder a su Runnable/Callable original. Decepcionante ... :(Parece que voy a anular el envío() también para mantener un Mapa de futuro a invocable. Espero que no disminuya demasiado las cosas. –

1

Creo que las otras dos respuestas son correctas, pero quizás un poco demasiado complicado (aunque mi respuesta, aunque simple, es probablemente no tan performante como la de ellos.

¿Por qué no utilizar las variables atómicas para realizar un seguimiento de sus estadísticas, como el número de tareas ejecutadas, el tiempo de ejecución total (dividido por el número total, obtiene el tiempo promedio de ejecución). Pase estas variables a Runnable para cada tarea. A menos que sus tareas sean de muy corta duración, no creo que la sobrecarga de el bloqueo de una variable atómica le afectará.

2

Otra forma es utilizar el patrón de envoltura/decorador

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); 
} 
} 
Cuestiones relacionadas