1

Multithreaded code私は、私たちのチームメイトコードのほとんどをベンチマークしようとしているときに、特定のメソッドにかかる時間を測定しようとしているところに取り組んでいLoad and Performanceます.Client codeService code

したがって、このパフォーマンス測定のために、私は使用しています-

System.nanoTime();

そして、複数のスレッドを生成し、そのコードにかかる時間を測定しようとしているマルチスレッドコードを持っています。

以下は、任意のコードのパフォーマンスを測定しようとしているサンプル例です-以下のコードでは、測定しようとしています-

beClient.getAttributes method

以下はコードです-

public class BenchMarkTest {

    public static void main(String[] args) {

        ExecutorService executor = Executors.newFixedThreadPool(5);

        try {

            for (int i = 0; i < 3 * 5; i++) {
                executor.submit(new ThreadTask(i));
            }

            executor.shutdown();
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
        } catch (InterruptedException e) {

        }
    }

}

以下はRunnableインターフェースを実装するクラスです

class ThreadTask implements Runnable {
    private int id;
    public static ConcurrentHashMap<Long, AtomicLong> selectHistogram = new ConcurrentHashMap<Long, AtomicLong>();


    public ThreadTask(int id) {
        this.id = id;
    }

    @Override
    public void run() {


        long start = System.nanoTime();

        attributes = beClient.getAttributes(columnsList);

        long end = System.nanoTime() - start;

        final AtomicLong before = selectHistogram.putIfAbsent(end / 1000000L, new AtomicLong(1L));
        if (before != null) {
            before.incrementAndGet();
        }
    }
}

測定したいコードが何であれ、通常はそのメソッドのすぐ上に以下の行を置きます

long start = System.nanoTime();

そして、これらの2行は同じ方法の後にありますが、ConcurrentHashMap

long end = System.nanoTime() - start;

final AtomicLong before = selectHistogram.putIfAbsent(end / 1000000L, new AtomicLong(1L));
        if (before != null) {
            before.incrementAndGet();
        }

今日、私は先輩の一人と面会しましたが、彼はincrementAndGet方法ConcurrentHashMapはブロッキングコールだと言いました. したがって、スレッドはそこでしばらく待機します。

そして彼は私にそれを作るように頼んだAsynchronous call

その非同期呼び出しを行う可能性はありますか?

すべてのクライアント コードとサービス コードで各メソッドのパフォーマンスを測定するため、通常は各メソッドの前後に配置するのと同じ上記の 3 行を使用して、これらのメソッドのパフォーマンスを測定します。プログラムが終了したら、それらのマップの結果を出力します。

だから今私はそれを作ることを考えていAsynchronous callますか?誰でも私がそれをするのを手伝ってくれますか?

基本的に、各スレッドが待機してブロックされないように、特定のメソッドのパフォーマンスを非同期で測定しようとしています。

を使用してこれを行うことができると思いますFutures。誰かがそれに関連する例を提供できますか?

助けてくれてありがとう。

4

2 に答える 2

1

この線:

if (before != null) {
    before.incrementAndGet();
}

ロックを取得するまで現在のスレッドbefore.incrementAndGet()をロックし (実際にはロックがなくwhile(true)compare-and-swapメソッドがあることを知っておく必要がある場合)、(使用していない) long 値を返します。

独自のスレッドでその特定のメソッドを呼び出すことにより、非同期にすることができるため、現在のスレッドをブロックしません。

Thread.start()これを行うには、 、 anExecutorServiceまたは aを使用する方法を既に知っていると思いますFutureTask(エレガントな方法でそれを行う方法については、「Java でメソッドを非同期的に呼び出す方法」を参照してください)。

よくわからない場合のために、次を使用したソリューションを示しFutureTaskます。

public class BenchMarkTest {

    public static void main(String[] args) {

        ExecutorService executor = Executors.newFixedThreadPool(5);

        int threadNum = 2;
        ExecutorService taskExecutor = Executors.newFixedThreadPool(threadNum);
        List<FutureTask<Long>> taskList = new ArrayList<FutureTask<Long>>();

        try {

            for (int i = 0; i < 3 * 5; i++) {
                executor.submit(new ThreadTask(i, taskExecutor, taskList));
            }

            executor.shutdown();
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
        } catch (InterruptedException e) {

        }

        for (FutureTask<Long> futureTask : taskList) {
            futureTask.get(); // doing a job similar to joining threads
        }
        taskExecutor.shutdown();
    }

}

ThreadTaskクラス:

class ThreadTask implements Runnable {
    private int id;
    public static ConcurrentHashMap<Long, AtomicLong> selectHistogram = new ConcurrentHashMap<Long, AtomicLong>();

    private ExecutorService taskExecutor;
    private List<FutureTask<Long>> taskList;    

    public ThreadTask(int id, ExecutorService taskExecutor, List<FutureTask<Long>> taskList) {
        this.id = id;
        this.taskExecutor = taskExecutor;
        this.taskList = taskList;
    }

    @Override
    public void run() {


        long start = System.nanoTime();

        attributes = beClient.getAttributes(columnsList);

        long end = System.nanoTime() - start;

        final AtomicLong before = selectHistogram.putIfAbsent(end / 1000000L, new AtomicLong(1L));
        if (before != null) {
            FutureTask<Long> futureTask = new FutureTask<Long>(new Callable<Long>() {
                public Long call() {
                    return before.incrementAndGet();
                }
            });
            taskList.add(futureTask);
            taskExecutor.execute(futureTask);
        }
    }
}

アップデート:

クラスでtaskExecutorを実行するようにに指示する代わりに、メソッドの最後までタスクの実行を延期する方が良いかもしれません。つまり:futureTaskThreadTaskmain

の次の行を削除しますThreadTask.run()

            taskExecutor.execute(futureTask);

そして、main()あなたが持っている方法では:

        for (FutureTask<Long> futureTask : taskList) {
            futureTask.get(); // doing a job similar to joining threads
        }
        taskExecutor.shutdown();

タスクの実行を追加すると、次のようになります。

        taskExecutor.invokeAll(taskList);
        for (FutureTask<Long> futureTask : taskList) {
            futureTask.get(); // doing a job similar to joining threads
        }
        taskExecutor.shutdown();

(また、ThreadTaskExecutorServiceフィールドは使用されなくなるため、削除することもできます。)

この方法では、ベンチマークの実行中のオーバーヘッドはほとんどありません (オーバーヘッドはオブジェクトを に追加するtaskListだけです)。

完全に更新されたコード:

public class BenchMarkTest {

    public static void main(String[] args) {

        ExecutorService executor = Executors.newFixedThreadPool(5);

        List<FutureTask<Long>> taskList = new ArrayList<FutureTask<Long>>();

        try {

            for (int i = 0; i < 3 * 5; i++) {
                executor.submit(new ThreadTask(i, taskList));
            }

            executor.shutdown();
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
        } catch (InterruptedException e) {

        }

        int threadNum = 2;
        ExecutorService taskExecutor = Executors.newFixedThreadPool(threadNum);
        taskExecutor.invokeAll(taskList);
        for (FutureTask<Long> futureTask : taskList) {
            futureTask.get(); // doing a job similar to joining threads
        }
        taskExecutor.shutdown();
    }

}

-

class ThreadTask implements Runnable {
    private int id;
    public static ConcurrentHashMap<Long, AtomicLong> selectHistogram = new ConcurrentHashMap<Long, AtomicLong>();

    private List<FutureTask<Long>> taskList;    

    public ThreadTask(int id, List<FutureTask<Long>> taskList) {
        this.id = id;
        this.taskList = taskList;
    }

    @Override
    public void run() {


        long start = System.nanoTime();

        attributes = beClient.getAttributes(columnsList);

        long end = System.nanoTime() - start;

        final AtomicLong before = selectHistogram.putIfAbsent(end / 1000000L, new AtomicLong(1L));
        if (before != null) {
            FutureTask<Long> futureTask = new FutureTask<Long>(new Callable<Long>() {
                public Long call() {
                    return before.incrementAndGet();
                }
            });
            taskList.add(futureTask);
        }
    }
}
于 2013-04-13T06:17:01.793 に答える
0

オブジェクトを作成して ExecutorService に渡すAtomicLongよりも、オブジェクトをインクリメントする方が時間がかからないと確信しています。Runnable/Callableこれが本当にボトルネックの原因ですか?本当に高速な同時インクリメントが必要な場合は、JDK8 に含まれるLongAdderを参照してください。

LongAdders を ConcurrentHashMap と共に使用して、スケーラブルな頻度マップ (ヒストグラムまたはマルチセットの形式) を維持できます。たとえば、ConcurrentHashMap freqs にカウントを追加するには、まだ存在しない場合は初期化して、freqs.computeIfAbsent(k -> new LongAdder()).increment(); を使用できます。

于 2013-04-13T06:19:48.197 に答える