То есть, два примера консольных программ на Java каждая,
в первом случае когда программа написана в императивном стиле (можно с ООП),
а во втором случае, когда эта же самая программа написана в функциональном стиле (с монадами).
Хочу увидеть, как вторая программа сама задействует многоядерность и обгоняет первую в 28 раз (по числу ядер).
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-ядерного процессора.
Здравствуйте, Эйнсток Файр, Вы писали:
ЭФ>То есть, два примера консольных программ на Java каждая, ЭФ>в первом случае когда программа написана в императивном стиле (можно с ООП),
В первом случае вы сами явно создаёте потоки выполняете действия, ждёте и собираете результат.
С ООП вы для всего этого еще делаете кучу классов и переходников.
ЭФ>а во втором случае, когда эта же самая программа написана в функциональном стиле (с монадами).
Тут вы говорите что надо сделать, и указываете что не плохо бы разбить на батчи и распараллелить (по числу ядер).
ЭФ>Хочу увидеть, как вторая программа сама задействует многоядерность и обгоняет первую в 28 раз (по числу ядер).
В идеале они должны работать с одинаковой скоростью.
Re[2]: Покажите, пожалуйста, профит от функционального программ
Здравствуйте, Эйнсток Файр, Вы писали:
vsb>> у меня получилось не с первого раза
ЭФ>Да, лишнее было создание объекта-точки в куче.
На самом деле нет.
long hits = stream
.filter(iteration -> {
var random = ThreadLocalRandom.current();
double x = random.nextDouble();
double y = random.nextDouble();
return x * x + y * y <= 1;
})
.count();
Вот этот код работает в 2.5 раза медленней. Почему — не знаю. Видимо особенности реализации стримов. Вообще Java тут в каком-то плане свинью подкладывает, не самый лучший язык для таких вещей. Предполагаю, что на Rust всё будет гораздо лучше оптимизироваться (но проверять это, конечно, я не буду).
Пол Хьюдак в своей книге "The Haskell School of Music" написал, что
Haskell is quite a bit different from conventional imperative or object-oriented languages such as C, C++, Java, C#, and so on. It takes a different mind-set to
program in such a language, and appeals to the mathematically inclined and to those who seek purity and elegance in their programs.
Яндекс-переводчик дает такой перевод:
Haskell довольно сильно отличается от обычных императивных или объектно-ориентированных языков, таких как C, C++, Java, C# и так далее. Чтобы
программировать на таком языке, требуется иной склад ума, и он подходит как для математиков, так и для тех, кто стремится к чистоте и элегантности в своих программах.
Короче, нравится людям программировать на языках ФП. И не мешайте им! Если кто-то не понимает их, то это проблемы именно тех людей, а не тех, кому нравится ФП. Вот и весь профит!