Паралельний Stream API
Ви, ймовірно, вже знайомі з Stream API, його методами та принципом роботи (якщо ні, вивчіть цю тему, а потім поверніться до цього розділу).
Звичайний потік даних не є паралельним, тобто, яким би зручним і красивим не був код, використання Stream API без методу parallelStream() при великій кількості даних може суттєво вплинути на продуктивність.
Існує також метод parallel(), який можна використовувати після перетворення у stream.
List<Integer> result = list.stream().parallel()
.map(num -> ++num)
.toList();
Відмінність полягає в тому, що parallelStream() створює паралельний потік безпосередньо з колекції, тоді як parallel() перетворює вже існуючий послідовний потік у паралельний потік.
І найголовніше — нам, як програмістам, не потрібно нічого робити, окрім заміни методу stream() на parallelStream(). Stream API все виконує самостійно та оптимізує нашу програму!
Приклад: Обробка списку чисел
Припустимо, у нас є список чисел, і ми хочемо знайти суму квадратів усіх чисел у цьому списку.
Main.java
123456789101112131415161718192021222324252627package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { // Create a list of integers List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // Sequential stream to sum the squares of numbers int sumSequential = numbers.stream() // Create a sequential stream from the list .mapToInt(n -> n * n) // Map each number to its square .sum(); // Sum the squares // Print the result of the sequential sum System.out.println("Sum of squares (sequential): " + sumSequential); // Parallel stream to sum the squares of numbers int sumParallel = numbers.parallelStream() // Create a parallel stream from the list .mapToInt(n -> n * n) // Map each number to its square .sum(); // Sum the squares // Print the result of the parallel sum System.out.println("Sum of squares (parallel): " + sumParallel); } }
Як видно, ми просто замінили stream() на parallelStream() І ЦЕ ВСЕ. У цьому прикладі це не дасть жодного виграшу, оскільки в однопотоковому середовищі масив із 10 символів буде виконано швидше. Оскільки в реалізації Stream API виконується багато дій для розподілу завдання між потоками.
Stream API також самостійно визначає, скільки потоків буде використовувати для цього завдання, щоб забезпечити максимальну ефективність.
Як це працює під капотом:
1. Створення паралельного потоку: Коли ви викликаєте parallelStream(), Java створює паралельний потік на основі початкового джерела даних;
2. Використання ForkJoinPool (розглянемо пізніше): Паралельні потоки використовують спільний пул потоків, ForkJoinPool.commonPool(), який керує групою робочих потоків;
3. Розбиття: Дані у паралельному потоці діляться на частини за допомогою інтерфейсу Spliterator;
4. Обробка: Кожен робочий потік у ForkJoinPool обробляє свою частину даних;
5. Об'єднання: Після обробки даних робочі потоки об'єднують результати.
Переваги паралельних потоків
Підвищення продуктивності є однією з ключових переваг паралельних потоків, оскільки вони дозволяють розподіляти завдання між кількома потоками, що забезпечує швидшу обробку на багатоядерних процесорах.
Крім того, простота використання API паралельних потоків дозволяє легко інтегрувати їх у існуючий код, усуваючи необхідність у складному керуванні потоками.
Також значною перевагою є масштабованість, оскільки паралельні потоки автоматично підлаштовуються під кількість доступних ядер процесора, оптимізуючи виконання завдань.
1. Який клас використовується паралельними потоками для керування потоками?
2. Який метод використовується для створення паралельного потоку?
3. Яку роль виконує інтерфейс Spliterator у контексті паралельних потоків?
Дякуємо за ваш відгук!
Запитати АІ
Запитати АІ
Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат
Can you explain when it's best to use parallel streams versus regular streams?
What are some potential drawbacks or risks of using parallel streams?
Can you provide more examples of using parallel streams in Java?
Awesome!
Completion rate improved to 3.33
Паралельний Stream API
Свайпніть щоб показати меню
Ви, ймовірно, вже знайомі з Stream API, його методами та принципом роботи (якщо ні, вивчіть цю тему, а потім поверніться до цього розділу).
Звичайний потік даних не є паралельним, тобто, яким би зручним і красивим не був код, використання Stream API без методу parallelStream() при великій кількості даних може суттєво вплинути на продуктивність.
Існує також метод parallel(), який можна використовувати після перетворення у stream.
List<Integer> result = list.stream().parallel()
.map(num -> ++num)
.toList();
Відмінність полягає в тому, що parallelStream() створює паралельний потік безпосередньо з колекції, тоді як parallel() перетворює вже існуючий послідовний потік у паралельний потік.
І найголовніше — нам, як програмістам, не потрібно нічого робити, окрім заміни методу stream() на parallelStream(). Stream API все виконує самостійно та оптимізує нашу програму!
Приклад: Обробка списку чисел
Припустимо, у нас є список чисел, і ми хочемо знайти суму квадратів усіх чисел у цьому списку.
Main.java
123456789101112131415161718192021222324252627package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { // Create a list of integers List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // Sequential stream to sum the squares of numbers int sumSequential = numbers.stream() // Create a sequential stream from the list .mapToInt(n -> n * n) // Map each number to its square .sum(); // Sum the squares // Print the result of the sequential sum System.out.println("Sum of squares (sequential): " + sumSequential); // Parallel stream to sum the squares of numbers int sumParallel = numbers.parallelStream() // Create a parallel stream from the list .mapToInt(n -> n * n) // Map each number to its square .sum(); // Sum the squares // Print the result of the parallel sum System.out.println("Sum of squares (parallel): " + sumParallel); } }
Як видно, ми просто замінили stream() на parallelStream() І ЦЕ ВСЕ. У цьому прикладі це не дасть жодного виграшу, оскільки в однопотоковому середовищі масив із 10 символів буде виконано швидше. Оскільки в реалізації Stream API виконується багато дій для розподілу завдання між потоками.
Stream API також самостійно визначає, скільки потоків буде використовувати для цього завдання, щоб забезпечити максимальну ефективність.
Як це працює під капотом:
1. Створення паралельного потоку: Коли ви викликаєте parallelStream(), Java створює паралельний потік на основі початкового джерела даних;
2. Використання ForkJoinPool (розглянемо пізніше): Паралельні потоки використовують спільний пул потоків, ForkJoinPool.commonPool(), який керує групою робочих потоків;
3. Розбиття: Дані у паралельному потоці діляться на частини за допомогою інтерфейсу Spliterator;
4. Обробка: Кожен робочий потік у ForkJoinPool обробляє свою частину даних;
5. Об'єднання: Після обробки даних робочі потоки об'єднують результати.
Переваги паралельних потоків
Підвищення продуктивності є однією з ключових переваг паралельних потоків, оскільки вони дозволяють розподіляти завдання між кількома потоками, що забезпечує швидшу обробку на багатоядерних процесорах.
Крім того, простота використання API паралельних потоків дозволяє легко інтегрувати їх у існуючий код, усуваючи необхідність у складному керуванні потоками.
Також значною перевагою є масштабованість, оскільки паралельні потоки автоматично підлаштовуються під кількість доступних ядер процесора, оптимізуючи виконання завдань.
1. Який клас використовується паралельними потоками для керування потоками?
2. Який метод використовується для створення паралельного потоку?
3. Яку роль виконує інтерфейс Spliterator у контексті паралельних потоків?
Дякуємо за ваш відгук!