1

いくつかの演習がありますが、そのうちの 1 つは同時実行性に関するものです。このテーマは私にとって新しいものですが、6 時間かけてようやく問題を解決しました。しかし、対応する API の知識が乏しいので、アドバイスが必要です: 私の解決策は正しいですか、それとももっと適切な方法があるかもしれません。

したがって、次のインターフェイスを実装する必要があります。

public interface PerformanceTester {    
    /**
     * Runs a performance test of the given task.
     * @param task which task to do performance tests on
     * @param executionCount how many times the task should be executed in total
     * @param threadPoolSize how many threads to use
     */
    public PerformanceTestResult runPerformanceTest(
            Runnable task,
            int executionCount, 
            int threadPoolSize) throws InterruptedException;
}

PerformanceTestResultには、合計時間 (パフォーマンス テスト全体の合計所要時間)、最小時間 (最短の 1 回の実行にかかった時間)、および最大時間 (最長の 1 回の実行にかかった時間) が含まれます。

そのため、今日、スレッド プール、タイプ、、、などについて多くの新しいことを学びましExecutorsた。ExecutorServiceFutureCompletionService

があれば Callable task、次に作ることができます:

  1. call()プロシージャの最後で現在の時刻を返します。
  2. Future開始時刻とオブジェクトを格納するためのデータ構造fixedThreadPool.submit(task)(いくつかの Map である可能性があります) を作成executionCountします。
  3. 実行後、すべての終了時間から開始時間を差し引くことができましたFuture

( Callable タスクの場合はこれでいいのでしょうか?)

しかし!しかないRunnable taskので、探し続けました。FutureListener implements Callable<Long>私は、時間を返さなければならない を作成しますFuture.isDone().

そのため、最終的に、次の完了したタスクを表す Futureを取得して削除し、まだ存在しない場合は待機する、CompletionService興味深いメソッドを持つ型に気付きました。、およびExecutorCompletionServiceを使用した非常に良い例です。そして、私の解決策があります。take()

public class PerformanceTesterImpl implements PerformanceTester {


@Override
public PerformanceTestResult runPerformanceTest(Runnable task,
        int executionCount, int threadPoolSize) throws InterruptedException {
    long totalTime = 0;
    long[] times = new long[executionCount];

    ExecutorService pool = Executors.newFixedThreadPool(threadPoolSize);

    //create list of executionCount tasks 
    ArrayList<Runnable> solvers = new ArrayList<Runnable>();
    for (int i = 0; i < executionCount; i++) {
        solvers.add(task);
    }

    CompletionService<Long> ecs = new ExecutorCompletionService<Long>(pool);

    //submit tasks and save time of execution start
    for (Runnable s : solvers)
        ecs.submit(s, System.currentTimeMillis());

    //take Futures one by one in order of completing
    for (int i = 0; i < executionCount; ++i) {
        long r = 0;
        try {
            //this is saved time of execution start
            r = ecs.take().get();
        } catch (ExecutionException e) {
            e.printStackTrace();
            return null;
        }
        //put into array difference between current time and start time
        times[i] = System.currentTimeMillis() - r;
        //calculate sum in array
        totalTime += times[i];
    }

    pool.shutdown();
    //sort array to define min and max
    Arrays.sort(times);        

    PerformanceTestResult performanceTestResult = new PerformanceTestResult(
            totalTime, times[0], times[executionCount - 1]);
    return performanceTestResult;
}
}

それで、あなたは何を言うことができますか?返信ありがとうございます。

4

2 に答える 2

3

より高い解像度のタイミングには System.nanoTime() を使用します。JVM がウォームアップしたことを確認するために、最初の 10,000 回のテストを無視することをお勧めします。

Runnable の List を作成して Executor に追加する必要はありません。代わりに、それらをエグゼキュータに追加します。

Runnable を使用しても問題はありませんFuture<?>

注: タスクがキューに留まる時間を計測することで、タイミングに大きな違いが生じる可能性があります。タスクが作成されてからの時間を取得する代わりに、タスクの時間自体を取得し、ナノ秒単位の時間の Long を返すことができます。タイミングの実行方法は、考えているユース ケースを反映する必要があります。


Runnable タスクを自分自身の時間を計測するタスクに変換する簡単な方法。

finla Runnable run = ...
ecs.submit(new Callable<Long>() {
    public Long call() {
         long start = System.nanoTime();
         run.run();
         return System.nanoTime() - start;
    }
});
于 2013-03-08T22:57:56.440 に答える
1

JVM でパフォーマンス テストを作成する場合、多くの複雑な点があります。これは演習であるため、おそらくそれらについて心配する必要はありませんが、この質問に詳しい情報がある場合は 、Java で正しいマイクロベンチマークを作成するにはどうすればよいですか?

とはいえ、コードに目立ったバグはないようです。コードの完全なレビューが必要な場合は、トラフィックの少ないコード レビュー サイト ( http://codereview.stackexchange.com ) で質問することをお勧めします。

于 2013-03-08T22:59:11.097 に答える