Как отслеживать статистику выполнения задач, используя ExecutorService? - PullRequest
8 голосов
/ 29 мая 2009

Я запускаю задачи с помощью ExecutorService, отправляя задачи, которые должны быть сгруппированы по критериям для конкретной задачи:

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

Периодически я хочу вывести среднюю продолжительность времени, которое занимало каждое задание (сгруппировано по type), а также статистическую информацию, такую ​​как среднее значение / медиана и стандартное отклонение.

Конечно, это должно быть довольно быстро и в идеале не должно вызывать синхронизацию различных потоков, когда они сообщают статистику. Какая архитектура для этого хороша?

Ответы [ 5 ]

9 голосов
/ 29 мая 2009

ThreadPoolExecutor предоставляет beforeExecute и afterExecute методы, которые вы можете переопределить. Вы можете использовать их, чтобы записать свою статистику в один (переменная-член вашей ExecutorService) ConcurrentHashMap , указав какой-то уникальный идентификатор для ваших задач и сохраняя тип, время начала и время окончания.

Рассчитать статистику из ConcurrentHashMap, когда вы будете готовы посмотреть на них.

4 голосов
/ 29 мая 2009

Подкласс Исполнитель пула потоков и отслеживание событий выполнения:

Стоит отметить, что методы вызываются рабочим потоком, который выполняет задачу, поэтому вам необходимо обеспечить безопасность потока для кода отслеживания выполнения.

Кроме того, Runnables, которые вы получите, скорее всего, будут не вашими Runnables, а обернутыми в FutureTasks.

2 голосов
/ 03 августа 2011

Другим способом является использование шаблона оболочки / декоратора.

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);
}
}
1 голос
/ 29 мая 2009

Я полагаю, что два других ответа верны, но, возможно, они слишком сложны (хотя мой ответ, хотя и простой, вероятно, не так эффективен, как их.

Почему бы просто не использовать атомарные переменные для отслеживания вашей статистики? Например, количество выполненных задач, общее время выполнения (деленное на общее количество, вы получаете среднее время выполнения). Передайте эти переменные в свой Runnable для каждой задачи. Если ваши задачи не будут слишком короткими, я не думаю, что накладные расходы на блокировку переменной Atomic повлияют на вас.

0 голосов
/ 15 октября 2018

Я согласен с @Robert Munteanu. beforeExecute в пуле потоков действительно ничего не стоит, хотя в документах сказано, что его можно использовать для статистики. Но на самом деле мы не можем проверить личность работающего в нашей ситуации.

Я думаю, что обертка может прийти сюда.

public interface ICallableHook<V> {
    void beforeExecute(Thread t, Callable<V> callable);
    void afterExecute(Callable<V> callable, V result, Throwable e);
}


private class CallableWrapper<V> implements Callable<V> {
        private ICallableHook hooker;
        private Callable<V> callable;

        CallableWrapper(Callable callable, ICallableHook hooker) {
            this.callable = callable;
            this.hooker = hooker;
        }




    @Override
    public V call() throws Exception {
        if (hooker != null) {
            hooker.beforeExecute(Thread.currentThread(), callable);
        }

        V result = null;
        Exception exception = null;
        try {
            result = callable.call();
        } catch (Exception e) {
            exception = e;
            throw e;
        } finally {
            if (hooker != null) {
                hooker.afterExecute(callable, result, exception);
            }
        }
        return result;
    }
}

Использование как это,

  for (Callable<XXX> callable : callableList) {
        CallableWrapper<XXX> callableWrapper = new CallableWrapper<>(callable, hooker);
        Future task = completionService.submit(callableWrapper);

    }
...