Java - вычислить PI - один против многопоточности - PullRequest
5 голосов
/ 20 июня 2019

Понятия не имею почему, но мой однопоточный код для вычисления PI намного быстрее, чем multi. Я использую 500 миллионов очков и для многопоточности 16 ядер. С одним процессором все нормально, а многопоточность - все 16 ядер на 100%, но медленнее ...

Любая подсказка ??

Single

    public static double monteCarloMethodSequencialMethod(long points) {
    long inCircle = 0;

    for (long i = 0; i < points; i++) {

        double x = Math.random();
        double y = Math.random();

        if(x * x + y * y <= 1) inCircle++;
    }

    return 4.0 * inCircle / points;
}

Последовательное значение PI для Монте-Карло: 3.141562496. Выполнено за 13432,927304 мс.

Multi-Thread

    public double calculatePI() throws InterruptedException, ExecutionException {

    double sum = 0;

    List<Future<Double>> tasks = new ArrayList<>();

    ExecutorService executor = Executors.newFixedThreadPool(nProcessors);

    for (long i = 0; i < points; i += points / nProcessors) {
        Future<Double> task = executor.submit(() -> {
            long inCircle = 0;
            double val = 0;

            for(long k = 0; k < points / nProcessors; k++) {
                double x = Math.random();
                double y = Math.random();

                if(x * x + y * y <= 1) inCircle++;
            }
            val = 4.0 * inCircle;

            return val;
        });

        tasks.add(task);
    }

    long pending = nProcessors;
    while(pending != 0) {
        for(Future<Double> future : tasks) {
            if(future.isDone()) {
                sum += future.get();
                pending--;
                System.out.println(pending + " task are still pending");
            }
        }
    }       

    executor.shutdown();

    return sum / points;
}

Одновременное значение PI для оценки по методу Монте-Карло: 3.141666048. Выполнено за 116236,812471 мс.

1 Ответ

4 голосов
/ 20 июня 2019

В вашем коде вы интенсивно используете случайные числа. Обратите внимание, что java.util.Random не идеален в такой ситуации, поскольку создает перегрузку между потоками. Это известная проблема производительности (источник документация ):

Экземпляры java.util.Random являются потокобезопасными. Однако одновременное использование одного и того же экземпляра java.util.Random между потоками может привести к конфликту и, как следствие, к низкой производительности. Вместо этого рассмотрите использование ThreadLocalRandom в многопоточных проектах.

Я бы рекомендовал вместо ThreadLocalRandom вместо:

java.util.concurrent.ThreadLocalRandom.current().nextDouble()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...