написать простой инструмент для сравнения в Java - PullRequest
2 голосов
/ 14 декабря 2011

Я хочу написать простой инструмент для тестирования производительности в java, который будет раскручивать x потоков и в общей сложности попадать в URL.

Фактическая часть задачи выполняет веб-запрос к URL и публикует файл XML.

Итак, что я хочу сделать, это раскрутить 50 потоков и продолжать нажимать на URL, пока я не сделаю 10K запросов.

Может кто-нибудь объяснить, как это сделать, я полагаю, использование службы Executor Service - это путь.

Некоторые вещи, которые следует учитывать:

  1. Как только поток закончится, я предполагаю, что он сразу же выполнит другую задачу правильно?
  2. Мне нужен поток для возврата, так как я должен отслеживать успехи / неудачи, где это должно храниться (он должен быть потокобезопасным).

Ответы [ 2 ]

3 голосов
/ 14 декабря 2011

Да, ExecutorService является идеальным выбором для этой задачи:

ExecutorService exec = Executors.newFixedThreadPool(50);

Запустите измерение времени и просто отправьте ему задания по 10 КБ:

for(int i = 0; i < 10000; ++i) {
  exec(new SubmitToUrlTask());
}

Рассмотрите возможность использования того же экземпляраof (без сохранения состояния или поточно-ориентированного) SubmitToUrlTask вместо создания нового в каждой итерации.

В конце вы должны дождаться окончания выполнения исполнителя:

exec.shutdown();
if(!exec.awaitTermination(1, TimeUnit.MINUTE)) {
  throw new IllegalStateException("Waiting for too long, captain!");
}

Прекратить измерениевремя сейчас.awaitTermination() блоков до всех задач завершено, но не дольше указанного времени (в примере 1 минута).

Как только поток закончен, я думаю, этонемедленно запустит другую задачу?

Да, ExecutorService - это группа потоков и очередь задач.Если поток не имеет ничего общего, он берет первую задачу из очереди.

Мне нужен поток для возврата, так как я должен отслеживать успехи / неудачи, где это должно храниться (он должен быть потокобезопасным).

Вы можете использовать Callable<Boolean> и Future<Boolean> для отслеживания результатов.Также, если вы используете только один экземпляр SubmitToUrlTask, он может иметь две переменные типа AtomicInteger, отслеживающие как успехи, так и неудачи.Это намного проще, если вам не нужно отслеживать отдельные результаты.

При этом вы уже рассматривали возможность использования JMeter , который обладает всеми этими функциями + гораздо больше из коробки?Также имеется консольная утилита ab.

1 голос
/ 15 декабря 2011

Вот аннотированный исходный код, который описывает стратегию, которую вы можете использовать:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class LoadGen {
    /**
     * Hits the given url for nRequests times on nUsers threads.
     *
     * @return LoadGen.Result object with status of the test
     */
    public static Result generateLoad(final String url,
        int nUsers, int nRequests) throws InterruptedException {
        // A thread pool with one thread per simulated user
        ExecutorService threadPool = Executors.newFixedThreadPool(nUsers);

        // A latch awaited on by the user threads before the test is started
        final CountDownLatch startSignal = new CountDownLatch(1);

        // A latch awaited on by the main thread for all user threads 
        // to complete the test
        final CountDownLatch doneSignal = new CountDownLatch(nUsers);

        // The Result object for this test run
        final Result result = new Result(nRequests);

        // Submit one Runnable per simulated user
        for (int i = 0; i < nUsers; i++) {
            threadPool.submit(new Runnable() {
                public void run() {
                    try {
                        // the Runnable awaits for the test to start
                        startSignal.await();

                        runSimulatedUser(url, result);

                        // indicate that this thread has completed
                        doneSignal.countDown();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

        // Start all simulated user threads
        startSignal.countDown();

        // Wait for all simulated user threads to complete the test
        doneSignal.await();

        // Dispose all threads
        threadPool.shutdownNow();
        return result;
    }

    private static void runSimulatedUser(String url, Result result) {
        // run repeatedly ..
        while (true) {
            try {
                // hitting the URL, marking success and failure
                // until nRequests requests are made in total
                makeRequest(url);
                if (! result.success()) {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
                if (! result.failure()) {
                    break;
                }
            }
        }
    }

    private static void makeRequest(String url) {
        // TODO: post the XML document to the URL etc
        System.out.println("Making request");
    }

    public static class Result {
        private final AtomicInteger nSuccess = new AtomicInteger();
        private final AtomicInteger nFailure = new AtomicInteger();
        private final AtomicInteger nTotal;

        public Result(int nTotal) {
            this.nTotal = new AtomicInteger(nTotal);
        }

        boolean success() {
            nSuccess.incrementAndGet();
            return nTotal.decrementAndGet() > 1;
        }

        boolean failure() {
            nFailure.incrementAndGet();
            return nTotal.decrementAndGet() > 1;
        }

        int getSuccessCount() {
            return nSuccess.get();
        }

        int getFailureCount() {
            return nFailure.get();
        }
    }

    public static void main(String[] args) throws Exception {
        // generate 10 requests on 2 threads
        LoadGen.generateLoad("http://myurl.com", 2, 10);
    }
}
...