Fork/Join Framework হলো জাভা কনকারেন্সি ফ্রেমওয়ার্কের একটি অংশ, যা Divide-and-Conquer কৌশল ব্যবহার করে টাস্কগুলোকে ছোট ছোট অংশে ভাগ করে Parallelism নিশ্চিত করে। এটি বড় কম্পিউটেশনাল কাজকে ছোট সাব-টাস্কে ভাগ করে একাধিক থ্রেডে কাজ করার অনুমতি দেয়।
Fork/Join Framework কী?
- Fork: কাজকে ছোট সাব-টাস্কে ভাগ করে।
- Join: সাব-টাস্কগুলোর ফলাফল একত্রিত করে।
- এটি জাভার java.util.concurrent প্যাকেজে অন্তর্ভুক্ত এবং
ForkJoinPoolএবংRecursiveTask/RecursiveActionএর মাধ্যমে কাজ করে।
Fork/Join Framework এর গঠন
- ForkJoinPool:
- একটি বিশেষ থ্রেড পুল, যেখানে কাজগুলো সাবমিট করা হয়।
- এটি
work-stealing algorithmব্যবহার করে।
- RecursiveTask:
- একটি ক্লাস যা টাস্কের কাজ শেষ হলে একটি রেজাল্ট প্রদান করে।
- RecursiveAction:
- একটি ক্লাস যা টাস্ক সম্পন্ন করে কিন্তু রেজাল্ট প্রদান করে না।
Fork/Join Framework ব্যবহার করার ধাপ
- একটি
RecursiveTaskবাRecursiveActionক্লাস তৈরি করুন। compute()মেথড ওভাররাইড করুন।- কাজকে ছোট অংশে ভাগ করে
fork()মেথড ব্যবহার করে সাবমিট করুন। - টাস্ক সম্পন্ন হলে
join()মেথড দিয়ে ফলাফল একত্রিত করুন।
উদাহরণ: RecursiveTask দিয়ে সংখ্যা যোগফল গণনা
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
class SumTask extends RecursiveTask<Long> {
private final int[] numbers;
private final int start;
private final int end;
private static final int THRESHOLD = 10; // টাস্ক ভাগ করার সীমা
public SumTask(int[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (end - start <= THRESHOLD) {
// ছোট টাস্ক সরাসরি সমাধান করা
long sum = 0;
for (int i = start; i < end; i++) {
sum += numbers[i];
}
return sum;
} else {
// কাজ ভাগ করা
int mid = (start + end) / 2;
SumTask leftTask = new SumTask(numbers, start, mid);
SumTask rightTask = new SumTask(numbers, mid, end);
leftTask.fork(); // সাবমিট করুন
long rightResult = rightTask.compute(); // ডান টাস্ক কম্পিউট করুন
long leftResult = leftTask.join(); // বাম টাস্কের রেজাল্ট নিয়ে আসুন
return leftResult + rightResult;
}
}
}
public class ForkJoinExample {
public static void main(String[] args) {
int[] numbers = new int[100];
for (int i = 0; i < numbers.length; i++) {
numbers[i] = i + 1; // 1 থেকে 100 পর্যন্ত সংখ্যা
}
ForkJoinPool pool = new ForkJoinPool(); // ForkJoinPool তৈরি
SumTask task = new SumTask(numbers, 0, numbers.length);
long result = pool.invoke(task); // কাজ শুরু করুন
System.out.println("Sum of numbers: " + result);
}
}
আউটপুট:
Sum of numbers: 5050
RecursiveAction দিয়ে কাজ (যেমন Sort করা)
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.ForkJoinPool;
import java.util.Arrays;
class MergeSortTask extends RecursiveAction {
private final int[] array;
private final int start;
private final int end;
private static final int THRESHOLD = 10;
public MergeSortTask(int[] array, int start, int end) {
this.array = array;
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if (end - start <= THRESHOLD) {
Arrays.sort(array, start, end); // ছোট অংশ সরাসরি সর্ট করুন
} else {
int mid = (start + end) / 2;
MergeSortTask leftTask = new MergeSortTask(array, start, mid);
MergeSortTask rightTask = new MergeSortTask(array, mid, end);
invokeAll(leftTask, rightTask); // দুইটি টাস্ক একসাথে চালান
merge(array, start, mid, end); // মার্জ করুন
}
}
private void merge(int[] array, int start, int mid, int end) {
int[] temp = Arrays.copyOfRange(array, start, end);
int i = 0, j = mid - start, k = start;
while (i < mid - start && j < end - start) {
array[k++] = (temp[i] <= temp[j]) ? temp[i++] : temp[j++];
}
while (i < mid - start) {
array[k++] = temp[i++];
}
while (j < end - start) {
array[k++] = temp[j++];
}
}
}
public class ForkJoinSortExample {
public static void main(String[] args) {
int[] array = {7, 2, 5, 3, 1, 8, 4, 6, 9};
ForkJoinPool pool = new ForkJoinPool(); // ForkJoinPool তৈরি
MergeSortTask task = new MergeSortTask(array, 0, array.length);
pool.invoke(task); // কাজ শুরু করুন
System.out.println("Sorted Array: " + Arrays.toString(array));
}
}
আউটপুট:
Sorted Array: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Fork/Join Framework এর বৈশিষ্ট্য
- Parallelism: একাধিক থ্রেড একসাথে কাজ করতে পারে।
- Work-Stealing Algorithm: অলস থ্রেডগুলো অন্য ব্যস্ত থ্রেডের কাজ চুরি করে নেয়।
- Divide-and-Conquer Approach: বড় কাজকে ছোট অংশে ভাগ করে কার্যকারিতা বাড়ায়।
Fork/Join Framework এর সীমাবদ্ধতা
- ছোট কাজের জন্য কার্যকর নয় (Overhead বেশি হতে পারে)।
- কাজ ভাগ করার ভুল হলে পারফরম্যান্স কমে যেতে পারে।
Fork/Join Framework বড় আকারের কম্পিউটেশনাল কাজকে সহজ এবং কার্যকরভাবে সমাধান করার জন্য একটি শক্তিশালী টুল। এটি প্রোগ্রামের কার্যকারিতা বৃদ্ধি করতে এবং মাল্টিপ্রসেসিং সুবিধা কাজে লাগাতে সহায়ক। Parallelism নিশ্চিত করতে RecursiveTask এবং RecursiveAction সঠিকভাবে ব্যবহার করা গুরুত্বপূর্ণ।
ForkJoin Framework হলো জাভার কনকারেন্সি ফ্রেমওয়ার্কের একটি অংশ, যা জটিল টাস্কগুলোকে ছোট ছোট সাবটাস্কে বিভক্ত (divide) করে সমান্তরালভাবে (parallelly) এক্সিকিউট করার জন্য ব্যবহৃত হয়। এটি বিশেষত রিকার্সিভ ডিভাইড-অ্যান্ড-কনকার (divide-and-conquer) অ্যালগরিদমের জন্য কার্যকর।
ForkJoin Framework এর মূল ধারণা
- Fork: একটি বড় টাস্ককে ছোট ছোট সাবটাস্কে ভাগ করা।
- Join: সাবটাস্কগুলো শেষ হলে তাদের ফলাফল একত্রিত করা।
- Work Stealing: অব্যবহৃত থ্রেডগুলো অন্য ব্যস্ত থ্রেডের কাজ নিজেরা গ্রহণ করে।
ForkJoin Framework এর প্রয়োজনীয় ক্লাস
ForkJoinPool: এটি থ্রেড ম্যানেজমেন্টের জন্য ব্যবহৃত হয়। এটি একটি বিশেষ থ্রেড পুল যা কাজের সমান্তরাল এক্সিকিউশন পরিচালনা করে।RecursiveTask<V>: এটি একটি কাজ সম্পন্ন করার পরে একটি রিটার্ন ভ্যালু প্রদান করে।RecursiveAction: এটি এমন কাজের জন্য ব্যবহৃত হয় যা কোনো রিটার্ন ভ্যালু প্রদান করে না।
ForkJoin Framework এর একটি সাধারণ উদাহরণ
১. রিকার্সিভ টাস্ক ব্যবহার করে গণনা (RecursiveTask Example)
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
class SumTask extends RecursiveTask<Long> {
private static final int THRESHOLD = 10; // টাস্ক বিভক্ত করার জন্য থ্রেশহোল্ড
private final int start;
private final int end;
public SumTask(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (end - start <= THRESHOLD) {
// ছোট টাস্ক সরাসরি হিসাব
long sum = 0;
for (int i = start; i <= end; i++) {
sum += i;
}
return sum;
} else {
// বড় টাস্ক ভাগ করা
int mid = (start + end) / 2;
SumTask leftTask = new SumTask(start, mid);
SumTask rightTask = new SumTask(mid + 1, end);
// সাবটাস্ক চালু করা
leftTask.fork();
rightTask.fork();
// ফলাফল সংগ্রহ
long leftResult = leftTask.join();
long rightResult = rightTask.join();
return leftResult + rightResult;
}
}
}
public class ForkJoinExample {
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
// টাস্ক তৈরি
SumTask task = new SumTask(1, 100);
// টাস্ক চালু এবং ফলাফল সংগ্রহ
long result = forkJoinPool.invoke(task);
System.out.println("Sum from 1 to 100: " + result);
}
}
২. রিকার্সিভ অ্যাকশন ব্যবহার করে প্রিন্টিং (RecursiveAction Example)
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.ForkJoinPool;
class PrintTask extends RecursiveAction {
private static final int THRESHOLD = 10;
private final int start;
private final int end;
public PrintTask(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if (end - start <= THRESHOLD) {
// সরাসরি প্রিন্ট করা
for (int i = start; i <= end; i++) {
System.out.println(Thread.currentThread().getName() + " printing: " + i);
}
} else {
// টাস্ক বিভক্ত করা
int mid = (start + end) / 2;
PrintTask leftTask = new PrintTask(start, mid);
PrintTask rightTask = new PrintTask(mid + 1, end);
invokeAll(leftTask, rightTask);
}
}
}
public class RecursiveActionExample {
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
// টাস্ক তৈরি
PrintTask task = new PrintTask(1, 50);
// টাস্ক চালু করা
forkJoinPool.invoke(task);
}
}
ForkJoin Framework এর বৈশিষ্ট্য
- লক ফ্রি ডিজাইন: এটি থ্রেডের মধ্যে লকিং ছাড়া কাজ করে, যা পারফরম্যান্স বাড়ায়।
- ডিভাইড-অ্যান্ড-কনকার: বড় কাজকে ছোট অংশে ভাগ করার কৌশল।
- ওয়ার্ক স্টিলিং (Work Stealing): অলস থ্রেডগুলো ব্যস্ত থ্রেডের কাজ নিজেরা গ্রহণ করে।
ForkJoin Framework ব্যবহার করার সময় সতর্কতা
- টাস্কের আকার: টাস্ক ছোট হওয়া উচিত; অন্যথায় এটি বেশি সময় নেয়।
- রিকার্সিভ লেভেল: অযথা বেশি রিকার্সিভ কল করার কারণে স্ট্যাক ওভারফ্লো হতে পারে।
- থ্রেশহোল্ড সঠিকভাবে নির্ধারণ করুন: টাস্ক বিভক্ত করার থ্রেশহোল্ড ব্যালান্সড হওয়া উচিত।
ForkJoin Framework এর ব্যবহার ক্ষেত্র
- বড় ডেটা প্রক্রিয়াকরণ (Big Data Processing): ডেটা ভাগ করে দ্রুত প্রসেস করার জন্য।
- সমান্তরাল অ্যালগরিদম: যেমন, মার্স সার্ট বা কোয়িক সার্ট।
- গাণিতিক হিসাব: বড় পরিসরের যোগফল বা গাণিতিক অপারেশন পরিচালনা।
ForkJoin Framework জাভার কনকারেন্সি মডেলে একটি অত্যন্ত গুরুত্বপূর্ণ অংশ। এটি বড় কাজগুলোকে ছোট ছোট সাবটাস্কে ভাগ করে সমান্তরাল এক্সিকিউশন পরিচালনা করে, যা কর্মদক্ষতা এবং পারফরম্যান্স বৃদ্ধি করে। এটি বিশেষত ডিভাইড-অ্যান্ড-কনকার প্যাটার্নের জন্য উপযোগী।
RecursiveTask এবং RecursiveAction হলো জাভার Fork/Join Framework এর অংশ, যা কনকারেন্সি কার্যকরভাবে পরিচালনা করার জন্য ব্যবহৃত হয়। এই ফ্রেমওয়ার্ক বড় কাজগুলোকে ছোট টুকরোতে ভাগ করে একাধিক থ্রেডের মধ্যে সমান্তরালভাবে কার্য সম্পাদন করে।
RecursiveTask: রিটার্ন মান সহ কাজ ভাগ করা
RecursiveTask এমন একটি ক্লাস যা কাজ ভাগ করে এবং রেজাল্ট প্রদান করে। এটি সাধারণত divide-and-conquer প্যাটার্নে ব্যবহৃত হয়।
উদাহরণ: একটি সংখ্যার তালিকার যোগফল গণনা
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
class SumTask extends RecursiveTask<Integer> {
private final int[] numbers;
private final int start;
private final int end;
private static final int THRESHOLD = 10; // কাজ ভাগ করার সীমা
public SumTask(int[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
// যদি কাজ ছোট হয়, সরাসরি সমাধান করুন
if (end - start <= THRESHOLD) {
int sum = 0;
for (int i = start; i < end; i++) {
sum += numbers[i];
}
return sum;
} else {
// কাজ ভাগ করুন
int mid = (start + end) / 2;
SumTask leftTask = new SumTask(numbers, start, mid);
SumTask rightTask = new SumTask(numbers, mid, end);
leftTask.fork(); // সাবটাস্ক শুরু
int rightResult = rightTask.compute(); // ডানদিকের সাবটাস্ক সমাধান
int leftResult = leftTask.join(); // বামদিকের সাবটাস্ক থেকে রেজাল্ট পান
return leftResult + rightResult; // ফলাফল যোগ করুন
}
}
}
public class RecursiveTaskExample {
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
int[] numbers = new int[100];
for (int i = 0; i < numbers.length; i++) {
numbers[i] = i + 1;
}
SumTask task = new SumTask(numbers, 0, numbers.length);
int result = pool.invoke(task);
System.out.println("Sum: " + result);
}
}
RecursiveAction: রিটার্ন মান ছাড়া কাজ ভাগ করা
RecursiveAction একটি থ্রেড সেফ ক্লাস, যা কাজ ভাগ করে এবং কার্য সম্পাদন করে, কিন্তু কোনো রিটার্ন মান দেয় না।
উদাহরণ: একটি সংখ্যার তালিকার ডাবলিং
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.ForkJoinPool;
class DoubleTask extends RecursiveAction {
private final int[] numbers;
private final int start;
private final int end;
private static final int THRESHOLD = 10; // কাজ ভাগ করার সীমা
public DoubleTask(int[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
}
@Override
protected void compute() {
// যদি কাজ ছোট হয়, সরাসরি সমাধান করুন
if (end - start <= THRESHOLD) {
for (int i = start; i < end; i++) {
numbers[i] *= 2; // মান ডাবল করুন
}
} else {
// কাজ ভাগ করুন
int mid = (start + end) / 2;
DoubleTask leftTask = new DoubleTask(numbers, start, mid);
DoubleTask rightTask = new DoubleTask(numbers, mid, end);
invokeAll(leftTask, rightTask); // দুই সাবটাস্ক একসাথে চালান
}
}
}
public class RecursiveActionExample {
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
int[] numbers = new int[20];
for (int i = 0; i < numbers.length; i++) {
numbers[i] = i + 1;
}
DoubleTask task = new DoubleTask(numbers, 0, numbers.length);
pool.invoke(task);
System.out.println("Doubled Numbers:");
for (int num : numbers) {
System.out.print(num + " ");
}
}
}
RecursiveTask এবং RecursiveAction এর তুলনা
| বৈশিষ্ট্য | RecursiveTask | RecursiveAction |
|---|---|---|
| রিটার্ন মান | একটি মান প্রদান করে | কোনো মান প্রদান করে না |
| ব্যবহার | যেমন: গণনা, ফলাফল প্রয়োজন হলে | যেমন: লিস্ট আপডেট বা ফাইল প্রক্রিয়া |
| উদাহরণ | যোগফল গণনা, ফ্যাক্টোরিয়াল | মান ডাবল করা, ফাইল কপি |
RecursiveTask এবং RecursiveAction এর সুবিধা
- কাজ ভাগ করা: বড় কাজগুলো ছোট টুকরোতে ভাগ করা হয়।
- প্যারালালিজম: কাজগুলো একাধিক থ্রেডে সমান্তরালভাবে চালানো হয়।
- Fork/Join Framework: এটি সহজ করে দেয় কনকারেন্সি কার্য সম্পাদন।
RecursiveTaskব্যবহার করুন যখন রিটার্ন মান প্রয়োজন।RecursiveActionব্যবহার করুন যখন শুধু কাজ সম্পন্ন করলেই হয়।- Fork/Join Framework বড় এবং জটিল কাজকে দ্রুত এবং কার্যকরভাবে সমাধান করতে সহায়ক।
সঠিকভাবে ব্যবহার করলে এটির মাধ্যমে মাল্টিথ্রেডিং প্রোগ্রামের পারফরম্যান্স উল্লেখযোগ্যভাবে উন্নত করা সম্ভব।
Work Stealing Algorithm হলো একটি কার্যকর কনকারেন্সি মডেল, যা থ্রেডের মধ্যে কাজের ভারসাম্য (load balancing) নিশ্চিত করে। এটি বিশেষভাবে মাল্টি-প্রসেসর সিস্টেমে ব্যবহৃত হয়, যেখানে কাজগুলোকে সমানভাবে ভাগ করা এবং সুষ্ঠুভাবে সম্পন্ন করা হয়।
Work Stealing Algorithm কী?
Work Stealing Algorithm একটি পদ্ধতি যেখানে:
- প্রতিটি থ্রেড নিজের কাজের জন্য একটি পৃথক কাজের কিউ (queue) রাখে।
- যখন কোনো থ্রেড তার কিউতে কাজ খুঁজে পায় না (অর্থাৎ এটি খালি হয়ে যায়), তখন এটি অন্য থ্রেডের কিউ থেকে কাজ "চুরি" করে।
কীভাবে কাজ করে?
- প্রাথমিক কাজ বরাদ্দ:
- কাজগুলো (tasks) থ্রেডগুলোর মধ্যে ভাগ করা হয়, প্রতিটি থ্রেড তার নিজের কাজের কিউতে কাজ পায়।
- স্বাধীন কাজ সম্পন্ন:
- থ্রেডগুলো প্রথমে তাদের নিজস্ব কিউ থেকে কাজ সম্পন্ন করে।
- কাজ চুরি:
- যদি কোনো থ্রেডের কিউ খালি হয়ে যায়, তবে এটি অন্য একটি থ্রেডের কিউ থেকে কাজ নেয়।
- সাধারণত, অন্য থ্রেডের কিউর শেষ থেকে (লাস্ট-ইন ফার্স্ট-আউট পদ্ধতি) কাজ চুরি করা হয়।
Java Work Stealing Framework
জাভাতে Work Stealing Algorithm সমর্থন করার জন্য ForkJoinPool ব্যবহার করা হয়। এটি Java 7 এ প্রবর্তিত হয়েছিল এবং Java 8 এর পরে parallel streams এর জন্য এটি ডিফল্ট পুল হিসেবে ব্যবহৃত হয়।
ForkJoinPool এর বৈশিষ্ট্য:
- লক-ফ্রি ডেটা স্ট্রাকচার: এটি কাজের কিউ পরিচালনার জন্য লক-ফ্রি ডেটা স্ট্রাকচার ব্যবহার করে।
- ডিপ কাজ ভাগাভাগি: বড় কাজগুলোকে ছোট ছোট সাবটাস্কে ভাগ করে।
- প্যারালাল এক্সিকিউশন: মাল্টি-প্রসেসর কোরে সমানভাবে কাজ বিতরণ করে।
Work Stealing Algorithm উদাহরণ: ForkJoinPool ব্যবহার
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
public class WorkStealingExample {
// RecursiveTask ব্যবহার করে কাজ বিভক্ত
static class SumTask extends RecursiveTask<Integer> {
private final int[] numbers;
private final int start;
private final int end;
private static final int THRESHOLD = 10; // কাজ বিভক্ত করার থ্রেশোল্ড
public SumTask(int[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
if ((end - start) <= THRESHOLD) {
// সরাসরি যোগফল গণনা
int sum = 0;
for (int i = start; i < end; i++) {
sum += numbers[i];
}
return sum;
} else {
// কাজ ভাগ করে দুইটি নতুন টাস্কে বিভক্ত করা
int mid = (start + end) / 2;
SumTask leftTask = new SumTask(numbers, start, mid);
SumTask rightTask = new SumTask(numbers, mid, end);
// সাবটাস্ক চালু এবং তাদের ফলাফল যোগ করা
leftTask.fork(); // প্যারালাল এক্সিকিউশন
int rightResult = rightTask.compute();
int leftResult = leftTask.join();
return leftResult + rightResult;
}
}
}
public static void main(String[] args) {
// ডেটা ইনিশিয়ালাইজ
int[] numbers = new int[100];
for (int i = 0; i < numbers.length; i++) {
numbers[i] = i + 1;
}
// ForkJoinPool তৈরি
ForkJoinPool forkJoinPool = new ForkJoinPool();
// মূল টাস্ক শুরু
SumTask task = new SumTask(numbers, 0, numbers.length);
int result = forkJoinPool.invoke(task);
// ফলাফল প্রদর্শন
System.out.println("Sum of numbers: " + result);
}
}
Work Stealing Algorithm এর উপকারিতা
- লোড ব্যালেন্সিং: কাজ সমানভাবে ভাগ করা হয় এবং অনুপস্থিত থ্রেডকে কাজে লাগানো হয়।
- উচ্চ পারফরম্যান্স: লক-ফ্রি অপারেশন এবং প্যারালাল এক্সিকিউশন নিশ্চিত করে।
- স্কেলেবিলিটি: এটি মাল্টি-কোর সিস্টেমে স্কেল করে।
Work Stealing Algorithm এর সীমাবদ্ধতা
- জটিলতা: ছোট কাজ বেশি হলে কাজ চুরির খরচ বৃদ্ধি পায়।
- থ্রেড কনটেক্সট সুইচিং: কাজ চুরির সময় থ্রেড কনটেক্সট সুইচিং বেশি হলে পারফরম্যান্স কমে যেতে পারে।
- মেমোরি ব্যবহার: প্রতিটি থ্রেডের জন্য পৃথক কিউ থাকার কারণে বেশি মেমোরি ব্যবহার হয়।
Work Stealing Algorithm জাভার কনকারেন্সি ব্যবস্থায় একটি অত্যন্ত কার্যকর পদ্ধতি। এটি থ্রেডগুলোর মধ্যে কাজের ভারসাম্য নিশ্চিত করে এবং মাল্টি-কোর প্রসেসরের সর্বোত্তম ব্যবহার নিশ্চিত করে। ForkJoinPool এবং parallel streams এর মাধ্যমে এই অ্যালগরিদম সহজে ব্যবহার করা যায়।
ForkJoinPool হলো জাভা কনকারেন্সি ফ্রেমওয়ার্কের একটি গুরুত্বপূর্ণ অংশ, যা Divide and Conquer পদ্ধতির মাধ্যমে প্যারালেলিজম বা সমান্তরাল প্রক্রিয়াকরণ সক্ষম করে। এটি বড় কাজকে ছোট ছোট সাবটাস্কে বিভক্ত করে একাধিক থ্রেডে প্যারালেল প্রসেসিং করে।
ForkJoinPool এর বৈশিষ্ট্য
- Divide and Conquer প্যাটার্ন: বড় কাজ ছোট টাস্কে ভাগ হয়।
- Work Stealing Algorithm: যদি একটি থ্রেড কাজ শেষ করে ফেলে, এটি অন্য ব্যস্ত থ্রেডের কাজ গ্রহণ করতে পারে।
- RecursiveTask ও RecursiveAction: দুটি প্রধান ক্লাস ব্যবহৃত হয়:
RecursiveTask: রিটার্ন ভ্যালু সহ কাজের জন্য।RecursiveAction: কোনো রিটার্ন ভ্যালু ছাড়া কাজের জন্য।
ForkJoinPool এর সাধারণ উদাহরণ
১. রিটার্ন ভ্যালু সহ (RecursiveTask)
যেমন: একটি সংখ্যার অ্যারেতে সমস্ত উপাদান যোগ করার কাজ।
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
class SumTask extends RecursiveTask<Integer> {
private static final int THRESHOLD = 2; // কাজ ভাগ করার সীমা
private final int[] numbers;
private final int start;
private final int end;
public SumTask(int[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
if (end - start <= THRESHOLD) {
// ছোট অংশ সরাসরি যোগফল গণনা
int sum = 0;
for (int i = start; i < end; i++) {
sum += numbers[i];
}
return sum;
} else {
// বড় কাজ ভাগ করা
int mid = (start + end) / 2;
SumTask leftTask = new SumTask(numbers, start, mid);
SumTask rightTask = new SumTask(numbers, mid, end);
// সাবটাস্ক শুরু
leftTask.fork();
int rightResult = rightTask.compute();
int leftResult = leftTask.join();
// ফলাফল যোগ করা
return leftResult + rightResult;
}
}
}
public class ForkJoinSumExample {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
ForkJoinPool pool = new ForkJoinPool();
SumTask task = new SumTask(numbers, 0, numbers.length);
int result = pool.invoke(task);
System.out.println("Sum of array elements: " + result);
}
}
২. কোনো রিটার্ন ভ্যালু ছাড়া (RecursiveAction)
যেমন: একটি অ্যারের সব উপাদানকে ডাবল করা।
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.ForkJoinPool;
class DoubleArrayTask extends RecursiveAction {
private static final int THRESHOLD = 2; // কাজ ভাগ করার সীমা
private final int[] numbers;
private final int start;
private final int end;
public DoubleArrayTask(int[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if (end - start <= THRESHOLD) {
// ছোট অংশ সরাসরি প্রসেসিং
for (int i = start; i < end; i++) {
numbers[i] *= 2;
}
} else {
// বড় কাজ ভাগ করা
int mid = (start + end) / 2;
DoubleArrayTask leftTask = new DoubleArrayTask(numbers, start, mid);
DoubleArrayTask rightTask = new DoubleArrayTask(numbers, mid, end);
// সাবটাস্ক শুরু
invokeAll(leftTask, rightTask);
}
}
}
public class ForkJoinDoubleArrayExample {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
ForkJoinPool pool = new ForkJoinPool();
DoubleArrayTask task = new DoubleArrayTask(numbers, 0, numbers.length);
pool.invoke(task);
// ফলাফল প্রিন্ট
for (int num : numbers) {
System.out.print(num + " ");
}
}
}
ForkJoinPool এর কাস্টমাইজেশন
ডিফল্ট থ্রেড সংখ্যা হল প্রসেসরের সংখ্যা। তবে, কাস্টম থ্রেড সংখ্যা সেট করা সম্ভব:
ForkJoinPool customPool = new ForkJoinPool(4); // ৪টি থ্রেড সহ কাস্টম পুল
ForkJoinPool ব্যবহার: মূল সুবিধা
- লক-ফ্রি পারফরম্যান্স: কাজ ভাগ করে প্রসেসরের ব্যবহার সর্বাধিক করা হয়।
- প্যারালেল প্রসেসিং: বড় কাজ দ্রুত সমাধান করার জন্য উপযোগী।
- ডাইনামিক ওয়ার্ক লোড ম্যানেজমেন্ট: Work Stealing Algorithm ব্যবহার করে।
ForkJoinPool এর সীমাবদ্ধতা
- Recursion Depth: গভীর রিকার্সন বেশি হলে স্ট্যাক ওভারফ্লো হতে পারে।
- সঠিক থ্রেশোল্ড নির্ধারণের প্রয়োজন: যদি থ্রেশোল্ড ঠিক না হয়, পারফরম্যান্স কমতে পারে।
- Shared Resource Deadlock: একই রিসোর্সে একাধিক থ্রেড কাজ করলে ডেডলক হতে পারে।
ForkJoinPool জাভার মাল্টিপ্রসেসিং টাস্ক পরিচালনার একটি শক্তিশালী টুল। এটি বড় এবং জটিল কাজ দ্রুত সমাধান করার জন্য ব্যবহৃত হয়। RecursiveTask এবং RecursiveAction ব্যবহার করে বড় কাজ সহজে ছোট ছোট সাবটাস্কে ভাগ করা যায় এবং সমান্তরালভাবে প্রক্রিয়াকরণ করা যায়।
Read more