8


6

ExecutorServiceを使用してタスク実行統計を追跡する方法

ExecutorServiceを使用してタスクを起動し、タスク固有の基準でグループ化する必要があるタスクをディスパッチします。

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

定期的に、各タスクにかかった平均時間(「+ type +」でグループ化)を、平均/中央値や標準偏差などの統計情報とともに出力します。

もちろんこれはかなり速くする必要があり、理想的には統計を報告するときにさまざまなスレッドを同期させるべきではありません。 これを行うための優れたアーキテクチャは何ですか?

5 Answer


9


ThreadPoolExecutorはhttp://java.sun.com/javase/6/docs/api/javaを提供します。 /util/concurrent/ThreadPoolExecutor.html#beforeExecute(java.lang.Thread,%20java.lang.Runnable)[beforeExecute]およびhttp://java.sun.com/javase/6/docs/api/java/util/ concurrent / ThreadPoolExecutor.html#afterExecute(java.lang.Runnable、%20java.lang.Throwable)[afterExecute]オーバーライドできるメソッド。 これらを使用して、統計情報を1つの(ExecutorServiceのメンバー変数)に記録することができます。http://java.sun.com/javase/6/docs/api/java/util/concurrent/ConcurrentHashMap.html[ConcurrentHashMap]タスクの一意の識別子と、種類、開始時刻、および終了時刻を格納します。

確認する準備ができたら、 `+ ConcurrentHashMap +`から統計を計算します。


4


http://java.sun.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html[Thread Pool Executor]をサブクラス化し、実行イベントを追跡します。

メソッドはタスクを実行するワーカースレッドによって呼び出されるので、実行追跡コードに対するスレッドの安全性を保証する必要があります。

また、あなたが受け取るRunnablesはたぶんあなたのRunnablesではないでしょうが、FutureTasksに包まれているでしょう。


2


別の方法はラッパー/デコレータパターンを使うことです。

パブリッククラスJobはRunnableを実装しています{private Runnable _task;プライベート統計

公開ジョブ(実行可能タスク、統計統計){this._task = task; }

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

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


1


私は他の2つの答えは正しいと思いますが、多少複雑すぎるかもしれません(私の答えは単純ではあるがおそらく彼らの答えほどパフォーマンスがよくないです)。

なぜあなたの統計を追跡するために単にAtomic変数を使わないのですか 実行されたタスクの数、合計実行時間(合計数で割ったもの、平均実行時間)。 タスクごとにこれらの変数をRunnableに渡します。 あなたのタスクが極端に短命ではない限り、私はAtomic変数をロックすることによるオーバーヘッドがあなたに影響を与えるとは思わない。


0


@Robert Munteanuに同意します。 スレッドプール内の `+ beforeExecute +`は、統計に使用できるとドキュメントが言っていても、実際には何の価値もありません。 しかし実際には、私達は私達の状況でランナブルのアイデンティティをチェックすることができません。

私はラッパーがこれに着くことができると思います。

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


private class CallableWrapper implements Callable {
        private ICallableHook hooker;
        private Callable 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 callable : callableList) {
        CallableWrapper callableWrapper = new CallableWrapper<>(callable, hooker);
        Future task = completionService.submit(callableWrapper);

    }