Информация об изменениях

Сообщение Re: Покажите, пожалуйста, профит от функционального программ от 04.08.2024 10:48

Изменено 04.08.2024 11:07 vsb

Re: Покажите, пожалуйста, профит от функционального программ
package test;

import static java.lang.Math.min;
import static java.lang.System.currentTimeMillis;

import java.util.concurrent.ThreadLocalRandom;
import java.util.function.DoubleSupplier;
import java.util.stream.IntStream;

public class Test {

  public static void main(String[] args) {
    run("Monte Carlo imperative", Test::monteCarloImperative, 5);
    run("Monte Carlo functional single-threaded", () -> monteCarloFunctional(false), 10);
    run("Monte Carlo functional multi-threaded", () -> monteCarloFunctional(true), 10);
  }

  static void run(String name, DoubleSupplier supplier, int count) {
    long bestTimeMillis = Long.MAX_VALUE;

    for (int counter = 0; counter < count; counter++) {
      long startTimeMillis = currentTimeMillis();
      supplier.getAsDouble();
      long endTimeMillis = currentTimeMillis();
      bestTimeMillis = min(bestTimeMillis, endTimeMillis - startTimeMillis);
    }

    System.out.printf("%s: best time %d ms%n", name, bestTimeMillis);
  }

  static final int ITERATIONS = 1_000_000_000;

  static double monteCarloImperative() {
    int hits = 0;
    var random = ThreadLocalRandom.current();
    for (int iteration = 0; iteration < ITERATIONS; iteration++) {
      double x = random.nextDouble();
      double y = random.nextDouble();
      if (x * x + y * y <= 1) {
        hits++;
      }
    }
    return (double) hits / ITERATIONS * 4;
  }

  static double monteCarloFunctional(boolean parallel) {
    record Point(double x, double y) {
    }

    IntStream stream;
    if (parallel) {
      stream = IntStream.range(0, ITERATIONS).parallel();
    } else {
      stream = IntStream.range(0, ITERATIONS);
    }

    long hits = stream
        .mapToObj(iteration -> {
          var random = ThreadLocalRandom.current();
          return new Point(random.nextDouble(), random.nextDouble());
        })
        .filter(point -> point.x() * point.x() + point.y() * point.y() <= 1)
        .count();

    return (double) hits / ITERATIONS * 4;
  }


}


Monte Carlo imperative: best time 3187 ms
Monte Carlo functional single-threaded: best time 7776 ms
Monte Carlo functional multi-threaded: best time 1097 ms


Функциональный стиль проигрывает примерно в 2.5 раза по скорости для однопоточного кода и выигрывает в 3 раза при использовании многопоточности.
Re: Покажите, пожалуйста, профит от функционального программ
package test;

import static java.lang.Math.PI;
import static java.lang.Math.abs;
import static java.lang.Math.min;
import static java.lang.System.currentTimeMillis;

import java.util.concurrent.ThreadLocalRandom;
import java.util.function.DoubleSupplier;
import java.util.stream.IntStream;

public class Test {

  public static void main(String[] args) {
    run("Monte Carlo imperative", Test::monteCarloImperative, 10);
    run("Monte Carlo functional single-threaded", () -> monteCarloFunctional(false), 10);
    run("Monte Carlo functional multi-threaded", () -> monteCarloFunctional(true), 10);
  }

  static void run(String name, DoubleSupplier supplier, int count) {
    long bestTimeMillis = Long.MAX_VALUE;

    for (int counter = 0; counter < count; counter++) {
      long startTimeMillis = currentTimeMillis();
      supplier.getAsDouble();
      long endTimeMillis = currentTimeMillis();
      bestTimeMillis = min(bestTimeMillis, endTimeMillis - startTimeMillis);
    }

    System.out.printf("%s: best time %d ms%n", name, bestTimeMillis);
  }

  static final int ITERATIONS = 1_000_000_000;

  static double monteCarloImperative() {
    int hits = 0;
    var random = ThreadLocalRandom.current();
    for (int iteration = 0; iteration < ITERATIONS; iteration++) {
      double x = random.nextDouble();
      double y = random.nextDouble();
      if (x * x + y * y <= 1) {
        hits++;
      }
    }
    return (double) hits / ITERATIONS * 4;
  }

  static double monteCarloFunctional(boolean parallel) {
    IntStream stream;
    if (parallel) {
      stream = IntStream.range(0, ITERATIONS).parallel();
    } else {
      stream = IntStream.range(0, ITERATIONS);
    }

    int hits = stream
        .map(iteration -> {
          var random = ThreadLocalRandom.current();
          double x = random.nextDouble();
          double y = random.nextDouble();
          return x * x + y * y <= 1 ? 1 : 0;
        })
        .sum();

    return (double) hits / ITERATIONS * 4;
  }


}


Monte Carlo imperative: best time 3183 ms
Monte Carlo functional single-threaded: best time 3205 ms
Monte Carlo functional multi-threaded: best time 473 ms


Функциональный стиль не проигрывает императивному для однопоточного кода и выигрывает примерно в 7 раза при использовании 8-ядерного процессора.