Java 8 Parallel Streams Sinhala Guide | වේගවත් Process කිරීම

Mastering Java 8 Parallel Streams | Sinhala Guide
Mastering Java 8 Parallel Streams | Sinhala Guide
ආයුබෝවන්! ✋ අද අපි කතා කරන්න යන්නේ Java programming වල තියෙන හරිම වැදගත් සහ ප්රායෝගික මාතෘකාවක් ගැන. ඒ තමයි Java 8 Parallel Streams. ඔබ දන්නවා ඇති, අද කාලේ තියෙන හැම computer එකකම වගේ multi-core CPUs තියෙනවා. ඒ කියන්නේ එක processor එකක cores කිහිපයක් තියෙනවා කියන එක. ඒත් අපි ලියන ගොඩක් programs තවමත් වැඩ කරන්නේ ඒ cores වලින් එකක් විතරයි පාවිච්චි කරලා, sequential විදියට. එතකොට අනිත් cores නිකරුණේ idling වෙනවා.
අන්න ඒකට විසඳුමක් තමයි Parallel Streams කියන්නේ. මේකෙන් පුළුවන් data processing operations කිහිපයක් එකම වෙලාවේ, එකට එකතු වෙලා cores කිහිපයක් පාවිච්චි කරලා කරන්න. ඒකෙන් අපේ applications වල speed එක ගොඩක් වැඩි කරගන්න පුළුවන්. විශේෂයෙන්ම විශාල data sets එක්ක වැඩ කරනකොට මේක ගොඩක් ප්රයෝජනවත් වෙනවා.
මේ tutorial එකෙන් අපි බලමු:
- Java Streams කියන්නේ මොනවාද කියලා කෙටි හැඳින්වීමක්.
- Parallel Streams වල වැදගත්කම සහ ඒවා භාවිතා කරන්නේ ඇයි කියලා.
- Parallel Streams හදන්නේ කොහොමද කියලා සරල code examples එක්ක.
- Parallel Streams පාවිච්චි කරන්න හොඳම අවස්ථා සහ පරිස්සම් වෙන්න ඕන දේවල්.
- සම්පූර්ණ ප්රායෝගික code example එකක්!
එහෙනම්, අපි පටන් ගමු!
Java Streams කියන්නේ මොනවාද? (කෙටි හැඳින්වීමක්)
Parallel Streams ගැන කතා කරන්න කලින්, අපි පොඩ්ඩක් මතක් කරගමු සාමාන්ය Java Streams කියන්නේ මොනවාද කියලා. Java 8 එක්ක තමයි මේ Streams කියන concept එක ආවේ. මේක අපිට පුළුවන් collection එකක තියෙන data ටික declarative විදියට handle කරන්න. ඒ කියන්නේ, අපි data එකට මොකද වෙන්න ඕනේ කියලා කියනවා මිසක්, ඒක කරන්නේ කොහොමද කියලා step-by-step කියන්නේ නෑ.
සරලව කිව්වොත්, Stream
එකක් කියන්නේ data sequence එකක්. මේකෙන් අපිට data filter කරන්න, map කරන්න (එක data type එකක් තව එකකට convert කරන්න), reduce කරන්න (data ගොඩක් එක result එකකට අඩු කරන්න) වගේ operations ගොඩක් කරන්න පුළුවන්. මේ operations කිසිම වෙලාවක original data source එක වෙනස් කරන්නේ නෑ. ඒවා lazy evaluation මත පදනම් වෙලා තියෙන්නේ, ඒ කියන්නේ අවසාන operation (terminal operation) එකක් කරනකම් ඇත්තටම calculation එකක් වෙන්නේ නෑ.
මෙන්න සරල Stream
example එකක්:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class SequentialStreamDemo {
public static void main(String[] args) {
List<String> names = Arrays.asList("Amal", "Nimal", "Kamal", "Saman", "Bimal");
// Stream එකක් පාවිච්චි කරලා 'a' අකුර තියෙන නම් filter කරලා, capital කරලා, අලුත් List එකකට ගන්නවා.
List<String> filteredAndMappedNames = names.stream()
.filter(name -> name.contains("a")) // 'a' අකුර තියෙන නම් විතරක් තෝරනවා
.map(String::toUpperCase) // තෝරාගත් නම් capital අකුරෙන් convert කරනවා
.collect(Collectors.toList()); // අලුත් List එකකට collect කරනවා
System.out.println("Filtered and Mapped Names: " + filteredAndMappedNames);
// Output: Filtered and Mapped Names: [AMAL, KAMAL, SAMAN]
}
}
මේ Stream
එක වැඩ කරන්නේ sequentially. ඒ කියන්නේ, operations ටික එකින් එක, එක thread එකක් පාවිච්චි කරලා කරනවා.
Parallel Streams භාවිතා කරන්නේ ඇයි?
අපි දැන් දන්නවා සාමාන්ය Streams වැඩ කරන්නේ කොහොමද කියලා. දැන් අපි බලමු Parallel Streams වල අවශ්යතාවය මොකක්ද කියලා.
අද තියෙන හැම computer එකකම වගේ multi-core processors තියෙනවා. Laptop එකක්, Desktop එකක්, Server එකක් වුණත් CPU cores 2ක්, 4ක්, 8ක් එහෙමත් නැත්නම් ඊට වැඩිය තියෙන්න පුළුවන්. සාමාන්යයෙන් Java applications sequential විදියට run වෙනකොට මේ cores වලින් එකක් විතරයි හරියටම පාවිච්චි වෙන්නේ. ඒ නිසා, අපිට විශාල data sets process කරන්න සිද්ධ වෙනකොට, වැඩේ ඉවර වෙන්න ගොඩක් වෙලා යනවා. Imagine කරන්න file එකක තියෙන million ගණන් records analyze කරනවා කියලා. Sequential stream එකකින් ඒක කරන්න ගියාම ගොඩක් slow වෙන්න පුළුවන්.
Parallel Streams කියන්නේ මේකට තියෙන නියම විසඳුමක්. මේකෙන් අපිට පුළුවන් එකම stream operation එකක් cores කිහිපයක් අතර බෙදලා දීලා, එකම වෙලාවේ වැඩේ කරවන්න. මේකෙන් data processing speed එක විශාල වශයෙන් වැඩි වෙනවා. මේක Java 8 වලදී ආපු හරිම බලගතු feature එකක්.
Parallel Streams වල වාසි:
- Performance Boost: Multi-core CPUs උපරිමයෙන් පාවිච්චි කරලා operations වල speed එක වැඩි කරනවා.
- Simplified Parallel Programming: සාමාන්යයෙන් multi-threading programming කියන්නේ ටිකක් සංකීර්ණ දෙයක්. Thread management, synchronization, deadlocks වගේ දේවල් ගැන හිතන්න වෙනවා. ඒත් Parallel Streams වලින් මේ හැම දෙයක්ම Java runtime එක ඇතුළතින්ම handle කරන නිසා, අපිට හරිම පහසුවෙන් parallel programming කරන්න පුළුවන්.
- Declarative Style: Stream API එකේ තියෙන declarative style එකම Parallel Streams වලටත් අදාළයි. ඒ නිසා code එක කියවන්න සහ maintain කරන්න පහසුයි.
Parallel Streams හදන්නේ කොහොමද?
Parallel Streams හදන එක හරිම ලේසියි. ප්රධාන ක්රම දෙකක් තියෙනවා:
1. Collection එකකින් කෙලින්ම Parallel Stream එකක් හදන එක:
ඔබට තියෙන Collection
එකක් (උදා: List
, Set
) direct parallelStream()
method එක පාවිච්චි කරලා Parallel Stream එකකට convert කරන්න පුළුවන්.
List<String> names = Arrays.asList("Amal", "Nimal", "Kamal", "Saman");
Stream<String> parallelNamesStream = names.parallelStream(); // මෙන්න Parallel Stream එකක්!
2. සාමාන්ය Stream එකක් Parallel එකක් බවට පත් කරන එක:
ඔබට දැනටමත් stream()
method එකෙන් හදාගත්තු sequential stream එකක් තියෙනවා නම්, ඒකට parallel()
method එක call කරලා ඒක parallel stream එකක් බවට පත් කරන්න පුළුවන්.
List<String> names = Arrays.asList("Amal", "Nimal", "Kamal", "Saman");
Stream<String> sequentialNamesStream = names.stream();
Stream<String> parallelNamesStream = sequentialNamesStream.parallel(); // sequential එක parallel කළා!
එච්චරයි! දැන් ඒ stream එකේ operations run වෙන්නේ parallel විදියට.
Parallel Streams භාවිතා කළ යුත්තේ කවදාද? (සහ නොකළ යුත්තේ කවදාද?)
Parallel Streams හැම වෙලාවෙම හොඳම විසඳුම නෙවෙයි. මේවා පාවිච්චි කරන්න ඕන නියම තැන දැනගෙන ඉන්න එක වැදගත්.
භාවිතා කළ යුතු අවස්ථා:
- විශාල Data Sets: ඔබ මිලියන ගණන් records වගේ විශාල data sets එක්ක වැඩ කරනවා නම්, Parallel Streams වලින් නියම performance boost එකක් ගන්න පුළුවන්.
- CPU-bound Operations: Operation එකකදී CPU එක ගොඩක් පාවිච්චි වෙනවා නම් (උදා: සංකීර්ණ ගණනය කිරීම්, image processing), Parallel Streams ඉතාමත් ප්රයෝජනවත්.
- Independent Operations: Stream එකේ තියෙන හැම element එකක්ම independently process කරන්න පුළුවන් නම් (එක element එකක result එකක් අනිත් එකට බලපාන්නේ නැත්නම්), Parallel Streams හොඳයි.
- Sufficient Number of Cores: ඔබේ computer එකේ CPU cores කිහිපයක් තියෙනවා නම් තමයි Parallel Streams වලින් වාසියක් ලැබෙන්නේ. Single-core CPU එකක Parallel Streams වලින් වැඩක් වෙන්නේ නෑ, සමහරවිට slow වෙන්නත් පුළුවන්.
භාවිතා නොකළ යුතු අවස්ථා (පරිස්සම් විය යුතු අවස්ථා):
- කුඩා Data Sets: පොඩි data sets වලට Parallel Streams පාවිච්චි කිරීමෙන් වාසියක් නෑ. Parallel Stream එකක් හදන්න සහ manage කරන්න overhead එකක් තියෙනවා. ඒ overhead එක නිසා පොඩි data set එකක් process කරන්න sequential stream එකකට වඩා වැඩි වෙලාවක් යන්න පුළුවන්.
- I/O-bound Operations: Database calls, network requests, file I/O වගේ operations වලදී CPU එකට වඩා I/O operations එකට තමයි වැඩි වෙලාවක් යන්නේ. මේවා Parallel කළා කියලා speed එක වැඩි වෙන්නේ නෑ. මොකද bottleneck එක CPU එක නෙවෙයි.
- Shared Mutable State: ඔබ Parallel Stream එකක් ඇතුළත Shared Mutable State (එකම variable එකකට threads කිහිපයක් access කරලා වෙනස් කරනවා නම්) පාවිච්චි කරනවා නම්, Thread Safety ගැන හිතන්න වෙනවා. මේක හරිම අවදානම්. Output එක unpredictable වෙන්න පුළුවන්. මේ වගේ අවස්ථා වලදී
Atomic
classes,synchronized
blocks හෝCollectors.groupingByConcurrent()
වගේ thread-safe collectors පාවිච්චි කරන්න වෙනවා. පුළුවන් නම් shared mutable state සම්පූර්ණයෙන්ම avoid කරන එක හොඳයි. - Order Dependency: සමහර operations වලට order එක වැදගත්. උදාහරණයක් විදියට, list එකක elements වල order එක 그대로 තියාගන්න ඕන නම්, Parallel Streams වල
forEachOrdered()
වගේ methods පාවිච්චි කරන්න වෙනවා. ඒත් මේකෙන් performance එක ටිකක් අඩු වෙන්න පුළුවන්.
ප්රායෝගික උදාහරණයක්: විශාල සංඛ්යා එකතු කිරීම
අපි දැන් බලමු විශාල සංඛ්යා ලැයිස්තුවක් Sequential සහ Parallel Streams දෙකම පාවිච්චි කරලා එකතු කරලා, ඒවායේ performance එක compare කරන්නේ කොහොමද කියලා.
මේ code එකෙන් අපි මිලියන 10ක random integers හදනවා. ඊට පස්සේ ඒවා sequential විදියටත්, parallel විදියටත් එකතු කරලා ඒකට යන වෙලාව print කරනවා.
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.Random;
public class ParallelStreamPerformanceDemo {
public static void main(String[] args) {
int listSize = 10_000_000; // මිලියන 10ක් සංඛ්යා
System.out.println("Generating a list of " + listSize + " random numbers...");
List<Integer> numbers = new Random()
.ints(listSize, 1, 100) // 1 ත් 99 ත් අතර random numbers හදනවා
.boxed() // int stream එක Integer stream එකක් කරනවා
.collect(Collectors.toList()); // List එකකට collect කරනවා
System.out.println("\nStarting sequential processing...");
long startTimeSequential = System.nanoTime(); // වෙලාව පටන් ගත්තා
long sumSequential = numbers.stream()
.mapToLong(Integer::longValue) // Overflow නොවෙන්න longValue එකට convert කරනවා
.sum(); // හැම එකතුවම ගන්නවා (reduce operation එකක්)
long endTimeSequential = System.nanoTime(); // වෙලාව ඉවරයි
long durationSequential = (endTimeSequential - startTimeSequential) / 1_000_000; // Milliseconds වලින් ගන්නවා
System.out.println("Sequential Sum: " + sumSequential + ", Time: " + durationSequential + " ms");
System.out.println("\nStarting parallel processing...");
long startTimeParallel = System.nanoTime(); // වෙලාව පටන් ගත්තා
long sumParallel = numbers.parallelStream()
.mapToLong(Integer::longValue)
.sum();
long endTimeParallel = System.nanoTime(); // වෙලාව ඉවරයි
long durationParallel = (endTimeParallel - startTimeParallel) / 1_000_000; // Milliseconds වලින් ගන්නවා
System.out.println("Parallel Sum: " + sumParallel + ", Time: " + durationParallel + " ms");
}
}
මේ code එක run කරලා බලන්න. ඔබේ computer එකේ CPU cores කීයක් තියෙනවද සහ hardware එකේ speed එක අනුව output එක වෙනස් වෙන්න පුළුවන්. හැබැයි, සාමාන්යයෙන් Parallel Stream එකෙන් වැඩේ කරන්න යන වෙලාව Sequential Stream එකට වඩා ගොඩක් අඩු වෙයි.
Expected Output (Example):
Generating a list of 10000000 random numbers...
Starting sequential processing...
Sequential Sum: 500000000, Time: 150 ms (ආසන්න වශයෙන්)
Starting parallel processing...
Parallel Sum: 500000000, Time: 50 ms (ආසන්න වශයෙන්)
මේ example එකේදී, Parallel Stream එක Sequential Stream එකට වඩා තුන් ගුණයක් විතර වේගවත් වෙලා තියෙනවා! 🚀
නිගමනය
ඉතින්, Java 8 Parallel Streams කියන්නේ අපේ Java applications වල performance එක වැඩි කරගන්න පුළුවන් හරිම powerful tool එකක්. Multi-core CPUs වල සම්පූර්ණ වාසිය ගන්න මේකෙන් පුළුවන්. ඒත් මේක පාවිච්චි කරන්න කලින්, ඔබේ use case එකට මේක ගැලපෙනවද කියලා හොඳට තේරුම් ගන්න එක වැදගත්.
මතක තියාගන්න:
- විශාල CPU-bound data processing operations වලදී Parallel Streams නියමයි.
- කුඩා data sets වලට සහ I/O-bound operations වලට Parallel Streams වලින් වාසියක් නෑ.
- Shared mutable state එක්ක වැඩ කරනකොට Thread Safety ගැන විශේෂයෙන් හිතන්න ඕන.
දැන් ඔබ Java Parallel Streams වල මූලික සංකල්පය සහ ඒවා භාවිතා කරන ආකාරය ගැන හොඳ අවබෝධයක් ඇති කියලා හිතනවා. මේ concepts අරගෙන ඔබේ projects වල අත්හදා බලන්න. Practical experience එකෙන් තමයි හොඳටම ඉගෙන ගන්න පුළුවන්.
මේ ගැන ඔබට තියෙන අත්දැකීම්, ප්රශ්න, නැත්නම් අලුත් අදහස් පහතින් comment කරන්න! 💬
තවත් අලුත් tutorial එකකින් හමු වෙමු! 👋