প্রায়োরিটি শিডিউলিং ও Round Robin
এই পাঠে যা শিখবেন
- প্রায়োরিটি শিডিউলিং, স্টার্ভেশন সমস্যা এবং aging সমাধান
- Round Robin অ্যালগরিদম এবং quantum size-এর trade-off
- Python দিয়ে একটি real Round Robin সিমুলেটর — ready-queue rotation ও প্রতিটি প্রসেসের completion/waiting time
- Python দিয়ে aging-সহ প্রায়োরিটি শিডিউলিং — একটি নিম্ন-প্রায়োরিটি প্রসেস কীভাবে ধীরে ধীরে "জিতে" যায়
১ · প্রায়োরিটি শিডিউলিং
প্রতিটি প্রসেসকে একটি প্রায়োরিটি নম্বর দেওয়া হয়; scheduler সবসময় READY প্রসেসগুলোর মধ্যে সর্বোচ্চ প্রায়োরিটিরটি চালায় (এই পাঠে আমরা সাধারণ কনভেনশন ব্যবহার করছি — কম সংখ্যা মানে বেশি প্রায়োরিটি)। এর একটি গুরুত্বপূর্ণ, বাস্তবে গুরুতর সমস্যা আছে — স্টার্ভেশন (Starvation)Starvationএকটি নিম্ন-প্রায়োরিটি প্রসেস কখনোই CPU না পাওয়ার ঝুঁকি, যদি উচ্চ-প্রায়োরিটি প্রসেস ক্রমাগত আসতে থাকে। — একটি নিম্ন-প্রায়োরিটি প্রসেস কখনোই না চলতে পারে যদি উচ্চ-প্রায়োরিটি প্রসেস আসতেই থাকে।
মানক সমাধান — AgingAgingএকটি অপেক্ষারত প্রসেসের প্রায়োরিটি সময়ের সাথে সাথে ধীরে ধীরে বাড়ানো, যাতে শেষ পর্যন্ত এটি চলার নিশ্চয়তা পায়। — একটি অপেক্ষারত প্রসেসের প্রায়োরিটি ক্রমশ বাড়াতে থাকা (আমাদের কনভেনশনে, effective priority-এর সংখ্যা কমাতে থাকা) যতক্ষণ না এটি অবশেষে সর্বোচ্চ প্রায়োরিটি পায় এবং চলার নিশ্চয়তা পায়।
২ · Round Robin
Round Robin প্রতিটি প্রসেসকে একটি নির্দিষ্ট ছোট time quantum দেয়; সেই quantum-এর মধ্যে প্রসেস শেষ না হলে এটি preempt হয়ে ready queue-এর একদম পেছনে গিয়ে বসে — বিশেষভাবে time-sharing/ইন্টারঅ্যাক্টিভ সিস্টেমের জন্য ডিজাইন করা, যাতে প্রতিটি প্রসেস নিয়মিত বিরতিতে CPU পায় (ন্যায্য, বাউন্ডেড response time)। এর মূল্য — কিছুটা context-switching overhead (L06)।
Quantum খুব বড় হলে Round Robin কার্যত FCFS-এর মতো আচরণ করে (response time খারাপ হয়)। quantum খুব ছোট হলে context-switching overhead (প্রতিটি সুইচে পিসিবি save/load, L06) সামগ্রিক কাজের তুলনায় অনেক বড় হয়ে যায় (throughput খারাপ হয়)। ব্যবহারিক সিস্টেমে quantum এমনভাবে বেছে নেওয়া হয় যাতে বেশিরভাগ ইন্টারঅ্যাক্টিভ বার্স্ট একটি quantum-এর মধ্যেই শেষ হয়ে যায়, কিন্তু খুব বড় নয় যে responsiveness নষ্ট হয়।
৩ · Round Robin সিমুলেশন — real কোডে
নিচের কোড সেলে quantum=2 নিয়ে ৩টি প্রসেসের একটি real Round Robin শিডিউলার বাস্তবায়ন করা হয়েছে — একটি
deque-ভিত্তিক ready queue প্রতি রাউন্ডে rotate হয়, এবং নতুন arrival-দের সঠিক মুহূর্তে queue-তে
যোগ করা হয়।
# Round Robin শিডিউলার -- সত্যিকারের অ্যালগরিদম, টয় প্রসেস ডেটার উপর
from collections import deque
processes = [
# (নাম, arrival_time, burst_time)
("P1", 0, 5),
("P2", 1, 4),
("P3", 2, 2),
]
quantum = 2
def round_robin(processes, quantum):
remaining = {name: burst for name, arrival, burst in processes}
arrival_of = {name: arrival for name, arrival, burst in processes}
order_by_arrival = sorted(processes, key=lambda p: p[1])
time = 0
queue = deque()
schedule = []
completion = {}
i = 0
def admit_new_arrivals(current_time):
nonlocal i
while i < len(order_by_arrival) and order_by_arrival[i][1] <= current_time:
queue.append(order_by_arrival[i][0])
i += 1
admit_new_arrivals(time)
if not queue:
time = order_by_arrival[0][1]
admit_new_arrivals(time)
while queue:
name = queue.popleft()
start = max(time, arrival_of[name])
run_time = min(quantum, remaining[name])
end = start + run_time
schedule.append((name, start, end))
remaining[name] -= run_time
time = end
admit_new_arrivals(time) # রান শেষে নতুন arrival যোগ, তারপরই বর্তমান প্রসেস (যদি বাকি থাকে) ফেরত
if remaining[name] > 0:
queue.append(name)
else:
completion[name] = time
waiting = {}
for name, arrival, burst in processes:
turnaround = completion[name] - arrival
waiting[name] = turnaround - burst
return schedule, completion, waiting
schedule, completion, waiting = round_robin(processes, quantum)
print(f"--- Round Robin (quantum={quantum}) ---")
print("এক্সিকিউশন অর্ডার (নাম, শুরু, শেষ):")
for name, start, end in schedule:
print(f" {name}: [{start} -> {end}]")
print("\nপ্রতিটি প্রসেসের completion ও waiting time:")
for name, arrival, burst in processes:
print(f" {name}: completion={completion[name]}, waiting={waiting[name]}")
avg_wait = sum(waiting.values()) / len(waiting)
print(f"\nগড় waiting time = {avg_wait:.2f}")
৪ · প্রায়োরিটি + Aging সিমুলেশন — স্টার্ভেশন প্রতিরোধ
এবার একটি নিম্ন-প্রায়োরিটি প্রসেস C (প্রায়োরিটি সংখ্যা ৮, খারাপ) কল্পনা করুন, যখন প্রতি রাউন্ডে
একটি নতুন উচ্চ-প্রায়োরিটি প্রসেস (প্রায়োরিটি সংখ্যা ৩) এসেই যাচ্ছে। Aging ছাড়া C
কখনোই CPU পেতো না — প্রতিটি নতুন জব সবসময় এর চেয়ে ভালো প্রায়োরিটিতে থাকতো। aging প্রয়োগ করে দেখা যাক
C-র effective priority ধীরে ধীরে কীভাবে বাড়ে (সংখ্যা কমে), এবং কখন এটি অবশেষে জেতে।
# প্রায়োরিটি শিডিউলিং + aging -- কম সংখ্যা = বেশি প্রায়োরিটি
# প্রতি রাউন্ডে একটি নতুন উচ্চ-প্রায়োরিটি জব (priority 3) আসে -- aging ছাড়া C কখনোই CPU পেতো না
c_priority = 8
aging_step = 2
new_job_priority = 3
round_num = 0
while True:
round_num += 1
new_job = f"J{round_num}"
ready = {new_job: new_job_priority, "C": c_priority}
chosen = min(ready, key=lambda n: ready[n])
print(f"রাউন্ড {round_num}: রেডি -> {ready} | নির্বাচিত: {chosen}")
if chosen == "C":
print(f"\n{round_num} রাউন্ড পর C-এর aged priority ({c_priority}) নতুন জবের priority "
f"({new_job_priority})-এর চেয়ে ভালো হয়ে গেলো -> C অবশেষে CPU পেলো (স্টার্ভেশন প্রতিরোধ হলো)")
break
c_priority -= aging_step
print(f" C স্কিপড হলো -> aging প্রয়োগ, C-এর নতুন effective priority = {c_priority}")
if round_num > 10:
print("সেফটি লিমিট -- থামানো হলো")
break
প্রায়োরিটি শিডিউলিং সহজ কিন্তু aging ছাড়া starvation-এর ঝুঁকিতে থাকে। Round Robin এই সমস্যা ভিন্নভাবে এড়ায় — কোনো প্রায়োরিটি প্রয়োজন নেই, শুধু নিয়মিত ঘূর্ণন দিয়ে প্রতিটি প্রসেসকে বাউন্ডেড সময়ের মধ্যে CPU দেওয়ার নিশ্চয়তা দেয়। L12-এর মাল্টিলেভেল ফিডব্যাক কিউ এই দুটি ধারণাকে একত্রিত করে আরও নমনীয় একটি ডিজাইন তৈরি করে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ উপরের Round Robin উদাহরণে P1-এর প্রথম রান ২ একক (quantum) দিয়ে শেষ হয়, পুরো burst (৫) দিয়ে নয় কেন?
Round Robin-এর মূল নিয়মই হলো কোনো প্রসেস তার পুরো burst একটানা চালাতে পারে না, quantum-এর বেশি হলে preempt হয়ে যায়। P1-এর burst (৫) quantum (২)-এর চেয়ে বড়, তাই এটি প্রথম রাউন্ডে মাত্র ২ একক চলে, বাকি ৩ একক নিয়ে queue-এর পেছনে গিয়ে বসে, এবং পরে আবার তার পালা এলে বাকিটা চালায়।
প্র ০২ যদি quantum-কে অনেক বড় করে দেওয়া হয় (যেমন ১০০), Round Robin আচরণে কী পরিবর্তন হবে?
যদি quantum প্রতিটি প্রসেসের burst time-এর চেয়েও বড় হয়ে যায়, প্রতিটি প্রসেস তার প্রথম রানেই সম্পূর্ণ শেষ হয়ে যাবে — কোনো preemption ঘটবে না, এবং ফলাফল কার্যত FCFS-এর সমান হয়ে যাবে (arrival অনুযায়ী ক্রম)। এটিই দেখায় quantum-এর আকার Round Robin-এর আচরণকে সরাসরি নিয়ন্ত্রণ করে।
প্র ০৩ Aging প্রয়োগ করার সময় aging_step (আমাদের উদাহরণে ২) খুব ছোট বা খুব বড় করলে কী সমস্যা হতে পারে?
aging_step খুব ছোট হলে C-এর প্রায়োরিটি বাড়তে অনেক রাউন্ড লাগবে — starvation দীর্ঘ সময় ধরে চলবে, aging কার্যত ধীর হবে। aging_step খুব বড় হলে C খুব দ্রুত (হয়তো ১-২ রাউন্ডেই) সর্বোচ্চ প্রায়োরিটি পেয়ে যেতে পারে, যা উল্টো দিকে অন্য (হয়তো সত্যিই জরুরি) উচ্চ-প্রায়োরিটি কাজকে বঞ্চিত করতে শুরু করবে — aging_step-ও তাই একটি বাস্তব trade-off, quantum size-এর মতোই।
অনুশীলন
-
চিন্তা করুন: আপনার কম্পিউটারের অপারেটিং সিস্টেম কেন সাধারণত pure Round Robin-এর বদলে একটি মাল্টিলেভেল ফিডব্যাক কিউ (L12) ব্যবহার করে, শুধু Round Robin ব্যবহার না করে?
Pure Round Robin সব প্রসেসকে সমানভাবে treat করে, তারা ইন্টারঅ্যাক্টিভ (দ্রুত রেসপন্স দরকার) হোক বা ব্যাচ/CPU-বাউন্ড (throughput দরকার) হোক। মাল্টিলেভেল ফিডব্যাক কিউ প্রসেসের প্রকৃত আচরণ পর্যবেক্ষণ করে (কে দ্রুত yield করছে বনাম কে পুরো quantum ব্যবহার করছে) এবং সেই অনুযায়ী প্রায়োরিটি/quantum সমন্বয় করে — বাস্তব ব্যবহারকারীর অভিজ্ঞতার জন্য এটি সাধারণত বেশি কার্যকর।
-
পরীক্ষা করুন: উপরের Round Robin কোড সেলে
quantum-কে ২ থেকে ১ করে দিন এবং দেখুন এক্সিকিউশন অর্ডারে কতগুলো (ছোট) ধাপ তৈরি হয় এবং গড় waiting time বদলায় কিনা।quantum=1 করলে প্রতিটি প্রসেস প্রতিবার মাত্র ১ একক করে চলবে, ফলে schedule তালিকায় অনেক বেশি (ছোট ছোট) এন্ট্রি দেখা যাবে — অর্থাৎ বাস্তবে অনেক বেশি context switch ঘটতো। গড় waiting time সামান্য বদলাতে পারে (কম quantum প্রায়ই responsiveness বাড়ায় কিন্তু overhead-ও বাড়ায়, যা এই সরলীকৃত সিমুলেশনে মডেল করা হয়নি)।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পরের পাঠ — মাল্টিলেভেল কিউ ও ফিডব্যাক কিউ শিডিউলিং L12 প্রায়োরিটি ও Round Robin-এর ধারণা মিলিয়ে কীভাবে একটি অভিযোজিত (adaptive) শিডিউলার তৈরি হয় তা দেখুন।
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৬টি পাঠ M3-এর শেষ পাঠ (L13) মাল্টিপ্রসেসর সিস্টেমে এই একই ধারণাগুলো কীভাবে সম্প্রসারিত হয় তা কভার করবে।
- Cloud Computing & DevOps কোর্স সঙ্গী কোর্স Kubernetes-এর মতো সিস্টেমে রিসোর্স প্রায়োরিটি ও fair scheduling কীভাবে ব্যবহারিকভাবে প্রয়োগ হয় তা দেখুন।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks ও Operating Systems — সব এক জায়গায়।