diff --git a/src/main/java/ru/lionarius/IntegralCalculator.java b/src/main/java/ru/lionarius/IntegralCalculator.java index 8cfdd02..b1f1243 100644 --- a/src/main/java/ru/lionarius/IntegralCalculator.java +++ b/src/main/java/ru/lionarius/IntegralCalculator.java @@ -1,11 +1,8 @@ package ru.lionarius; import java.util.ArrayList; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.*; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiConsumer; import java.util.function.Function; @@ -107,24 +104,75 @@ public class IntegralCalculator { this.callProgressCallback(0, n); + var remainder = n % parallelism; + var partitionSize = n / parallelism; + var currentStart = 0L; + var sum = (function.apply(lowerBound) + function.apply(upperBound)) / 2; + final var futures = new ArrayList>(); + final var semaphore = new Semaphore(2); + final var lock = new ReentrantLock(); + final var latch = new CountDownLatch(parallelism); + + var times = new long[parallelism]; + var totalProgress = new long[]{0L}; for (var i = 0; i < parallelism; i++) { - final var order = i; + final var start = currentStart; + final var end = currentStart + partitionSize + (remainder > 0 ? 1 : 0); + if (remainder > 0) + remainder--; + currentStart = end; + + final var innerI = i; + futures.add(executor.submit(() -> { var partitionSum = 0.0; - for (var j = order; j < n; j += parallelism) { - partitionSum += function.apply(lowerBound + h * j); + try { + semaphore.acquire(); - this.callProgressCallback(j, n); + for (var j = start; j < end; j++) { + partitionSum += function.apply(lowerBound + h * j); + + lock.lock(); + try { + totalProgress[0] += 1; + this.callProgressCallback(totalProgress[0], n); + } finally { + lock.unlock(); + } + } + + lock.lock(); + try { + times[innerI] = System.nanoTime(); + } finally { + lock.unlock(); + } + } finally { + semaphore.release(); } + + latch.countDown(); return partitionSum; })); } + latch.await(); + for (var future : futures) { - sum += future.get(); + sum += future.resultNow(); + } + + var minimumTime = Long.MAX_VALUE; + for (var time : times) { + if (time < minimumTime) + minimumTime = time; + } + + for (var i = 0; i < parallelism; i++) { + System.out.printf("Thread %d took %.6fms%n", i, (times[i] - minimumTime) / 1_000_000.0); } sum *= h; diff --git a/src/main/java/ru/lionarius/Main.java b/src/main/java/ru/lionarius/Main.java index 70f0248..c6fbd09 100644 --- a/src/main/java/ru/lionarius/Main.java +++ b/src/main/java/ru/lionarius/Main.java @@ -9,25 +9,28 @@ public class Main { Function function = x -> Math.sin(x) * x; var lowerBound = 0.0; var upperBound = 1.0; - double[] accuracies = {0.0001, 0.00001, 0.0000001, 0.000000001, 0.000000001}; + double[] accuracies = {0.0001, 0.00001, 0.0000001, 0.000000005}; - var executor = Executors.newCachedThreadPool(); + var executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); for (final var accuracy : accuracies) { var calculator = new IntegralCalculator( - accuracy + accuracy, + (i, n) -> { + if (i % (n / 15) == 0) + System.out.printf("[%s] Progress %f%%%n", Thread.currentThread().getName(), i / (double) n * 100.0); + } ); var startTime = System.nanoTime(); double value = 0; try { - value = calculator.calculate(function, lowerBound, upperBound, executor, 1); + value = calculator.calculate(function, lowerBound, upperBound, executor, 8); } catch (ExecutionException e) { System.err.println("Error calculating integral: " + e.getMessage()); } catch (InterruptedException e) { System.err.println("Thread interrupted: " + e.getMessage()); - executor.shutdown(); } var totalTime = System.nanoTime() - startTime;