1

我正在Multithreaded code努力测量一个特定方法所花费的时间,因为我正在尝试对我们的大多数队友代码进行基准测试,因为我正在Load and Performance测试我们的Client code,然后是我们的Service 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();

这两行采用相同的方法但不同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

是否有可能进行该异步调用?

因为在我们所有的客户端代码和服务代码中来衡量每个方法的性能,我使用上面相同的三行,我通常在每个方法之前和之后放置来衡量这些方法的性能。程序完成后,我将这些地图的结果打印出来。

所以现在我正在考虑做那个Asynchronous call?谁能帮我做到这一点?

基本上,我试图以异步方式测量特定方法的性能,以便每个线程不会等待并被阻塞。

我想,我可以使用Futures. 任何人都可以提供与此相关的示例吗?

谢谢您的帮助。

4

2 回答 2

1

该行:

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

将锁定当前线程,直到before.incrementAndGet()获得锁(如果您必须知道,实际上没有锁,有while(true)一个比较和交换方法)并返回长值(您没有使用)。

您可以通过在它自己的线程中调用该特定方法来使其异步,从而不会阻塞当前线程。

为此,我相信您已经知道如何使用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();

(此外,您可以删除ThreadTask'sExecutorService字段,因为它将不再使用它。)

这样,在执行基准测试时开销很小(开销是将对象添加到 the 中,仅此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

我确信增加一个对象比创建一个对象并将它传递给一个 ExecutorServiceAtomicLong花费的时间更少。Runnable/Callable这会导致你真的成为瓶颈吗?如果您真的想要快速并发增量,请参阅JDK8中的 LongAdder。

LongAdders 可以与 ConcurrentHashMap 一起使用,以维护可扩展的频率图(直方图或多重集的一种形式)。例如,要向 ConcurrentHashMap freqs 添加计数,如果不存在则进行初始化,您可以使用 freqs.computeIfAbsent(k -> new LongAdder()).increment();

于 2013-04-13T06:19:48.197 回答