Dispatchers Kotlin Coroutines-এ CoroutineContext-এর উপাদান যা coroutines সম্পাদনের জন্য থ্রেড নির্ধারণ করে: Main (UI থ্রেড), IO (নেটওয়ার্ক এবং ডিস্ক), Default (CPU-নিবিড় কাজ) এবং Unconfined (বর্তমান থ্রেড)। প্রতিটি ডিসপ্যাচার একটি বিশেষায়িত থ্রেড পুল পরিচালনা করে যা নির্দিষ্ট ধরণের কাজের জন্য অপ্টিমাইজ করা হয়েছে। JetBrains গাইড, 2024 অনুসারে, সঠিক ডিসপ্যাচার নির্বাচন করা অ্যাপ্লিকেশনের কর্মক্ষমতা এবং স্থিতিশীলতার জন্য গুরুত্বপূর্ণ।
মূল পয়েন্ট
Dispatchers হল CoroutineDispatcher ইন্টারফেসের বাস্তবায়ন, যা CoroutineContext-এর উপাদান। তারা নির্ধারণ করে কোন থ্রেড বা থ্রেড পুলে coroutine সম্পাদিত হবে। launch বা async-এর মাধ্যমে coroutine তৈরি করার সময়, ডিসপ্যাচারটি প্রথম প্যারামিটার হিসাবে পাস করা যেতে পারে: launch(Dispatchers.IO) { ... }। যদি কোনো ডিসপ্যাচার নির্দিষ্ট না করা হয়, তবে এটি বাইরের CoroutineScope থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হয়।
Kotlin চারটি অন্তর্নির্মিত ডিসপ্যাচার প্রদান করে: Main, IO, Default, Unconfined। প্রতিটি ডিসপ্যাচার নির্দিষ্ট ধরণের অপারেশনের জন্য অপ্টিমাইজ করা নিজস্ব থ্রেড পুল ব্যবহার করে। সঠিক ডিসপ্যাচার নির্বাচন অ্যাপ্লিকেশনের কর্মক্ষমতা নির্ধারণ করে: ভুল পছন্দ UI ল্যাগ, নিষ্ক্রিয় CPU কোর বা অদক্ষ থ্রেড ব্যবহারের দিকে নিয়ে যায়।
| ডিসপ্যাচার | থ্রেড পুল | সর্বোচ্চ থ্রেড | ব্যবহার |
|---|---|---|---|
| Dispatchers.Main | এক (UI) | 1 | UI আপডেট, LiveData, View |
| Dispatchers.IO | IO পুল | 64 (limitedParallelism) | নেটওয়ার্ক, ফাইল, DB |
| Dispatchers.Default | CPU পুল | N কোর | সাজানো, পার্সিং, গণনা |
| Dispatchers.Unconfined | বর্তমান থ্রেড | প্রযোজ্য নয় | মধ্যবর্তী অপারেশন, পরীক্ষা |
Dispatchers.Main হল ডিসপ্যাচার যা Android প্রধান থ্রেডে coroutines সম্পাদন করে। এটি UI-সম্পর্কিত অপারেশনের জন্য ডিজাইন করা হয়েছে: TextView আপডেট করা, notifyDataSetChanged কল করা, LiveData এবং StateFlow নিয়ে কাজ করা। Android-এ, এই ডিসপ্যাচারটি Handler (Looper.getMainLooper()) এর মাধ্যমে বাস্তবায়িত হয়।
// Correct switch to Main for UI updates
viewModelScope.launch(Dispatchers.IO) {
val data = repository.fetchData()
withContext(Dispatchers.Main) {
_uiState.value = data
}
}
যদি একটি coroutine ইতিমধ্যেই Main ডিসপ্যাচারে থাকে, তবে অতিরিক্ত withContext(Dispatchers.Main) কোনো ওভারহেড তৈরি করে না — ডিসপ্যাচার বর্তমান থ্রেড পরীক্ষা করে এবং সুইচ এড়িয়ে যায়। withContext হল ডিসপ্যাচারগুলির মধ্যে সুইচ করার পছন্দের উপায়।
Dispatchers.IO হল একটি ডিসপ্যাচার যা I/O অপারেশনের জন্য অপ্টিমাইজ করা: HTTP অনুরোধ (Ktor, OkHttp), ফাইল পড়া এবং লেখা, Room বা SQLDelight নিয়ে কাজ করা। এটি ডিফল্টভাবে 64 থ্রেড-এর একটি পুল ব্যবহার করে, যা লোডের অধীনে স্কেলযোগ্য। প্রতিটি নতুন I/O অনুরোধ সীমায় পৌঁছানো পর্যন্ত একটি অতিরিক্ত থ্রেড তৈরি করতে পারে।
সমন্বিত I/O অপারেশনের সংখ্যা নিয়ন্ত্রণ করতে, limitedParallelism() ব্যবহার করুন। এই ফাংশনটি সমান্তরাল থ্রেডের সংখ্যার সীমা সহ একটি নতুন ডিসপ্যাচার তৈরি করে, যা বাল্ক অপারেশনের সময় পুল শেষ হয়ে যাওয়া প্রতিরোধ করে।
val limitedIo = Dispatchers.IO.limitedParallelism(4)
// Load 100 files with limit of 4 concurrent operations
coroutineScope {
val files = (1..100).map { index ->
async(limitedIo) {
downloadFile("file_$index")
}
}
files.awaitAll()
}
সমস্ত অপারেশনের জন্য IO ডিসপ্যাচার ব্যবহার করুন যেখানে coroutine অপেক্ষায় সময় কাটায় (I/O-bound)। IO ডিসপ্যাচারে CPU-নিবিড় কাজ অদক্ষ — তারা I/O-র জন্য নির্ধারিত থ্রেড দখল করে, সিস্টেমের থ্রুপুট হ্রাস করে।
Dispatchers.Default হল কম্পিউটেশন অপারেশনের জন্য ডিসপ্যাচার যা প্রসেসর লোড করে: সাজানো, ফিল্টারিং, JSON পার্সিং (Moshi, Kotlinx Serialization), ইমেজ প্রসেসিং, গণনা। পুলের আকার প্রসেসর কোরের সংখ্যার সমান (কিন্তু 2-এর কম নয়)। এটি প্রসঙ্গ সুইচিং ছাড়াই সর্বাধিক CPU ব্যবহার নিশ্চিত করে।
suspend fun processData(input: List<RawRecord>): List<ProcessedRecord> {
return withContext(Dispatchers.Default) {
input
.parallelStream()
.map { transform(it) }
.toList()
}
}
I/O অপারেশনের জন্য Dispatchers.Default ব্যবহার করবেন না — এটি CPU পুলের থ্রেড ব্লক করবে যা কম্পিউটেশনাল কাজ প্রক্রিয়া করতে পারত। IO এবং Default আলাদা করা সিস্টেম সংস্থানের অনুকূল ব্যবহার নিশ্চিত করে: IO থ্রেড I/O-র জন্য অপেক্ষা করে, CPU থ্রেড ক্রমাগত গণনার সাথে ব্যস্ত থাকে।
Dispatchers.Unconfined হল একটি বিশেষ ডিসপ্যাচার যা coroutine-কে কোনো পুলের সাথে আবদ্ধ করে না। Coroutine যে থ্রেডে launch/async কল করা হয়েছিল সেখানে সম্পাদন শুরু করে এবং স্থগিত করার পরে যে থ্রেড resume কল করেছে সেখানে পুনরায় শুরু হয়। এই আচরণ মধ্যবর্তী অপারেশনের জন্য উপযুক্ত যার নির্দিষ্ট প্রসঙ্গের প্রয়োজন নেই।
fun main() = runBlocking {
launch(Dispatchers.Unconfined) {
println("Before delay: ${Thread.currentThread().getName()}")
delay(500L)
println("After delay: ${Thread.currentThread().getName()}")
}
}
প্রোডাকশন কোডে, Dispatchers.Unconfined খুব কমই ব্যবহৃত হয়। প্রধান ব্যবহারের ক্ষেত্রে: অন্য ডিসপ্যাচারে ডেটা পাস করার আগে হালকা রূপান্তর এবং পরীক্ষা। প্রোডাকশন ওয়ার্কলোডের জন্য, স্পষ্ট ডিসপ্যাচার ব্যবহার করুন — Unconfined অপ্রত্যাশিত কারণ সম্পাদন থ্রেড resume বাস্তবায়নের উপর নির্ভর করে।
ডিসপ্যাচার নির্বাচন কাজের ধরণের উপর নির্ভর করে: UI অপারেশন → Main, I/O-bound → IO, CPU-bound → Default, মধ্যবর্তী → scope থেকে উত্তরাধিকার। Android-এর জন্য, coroutine সেই ডিসপ্যাচারে লঞ্চ করার পরামর্শ দেওয়া হয় যেখানে মূল কাজ সম্পাদিত হয়, এবং UI আপডেট করার আগে withContext-এর মাধ্যমে Main-এ সুইচ করুন।
জটিল পরিস্থিতির জন্য, + অপারেটর ব্যবহার করে ডিসপ্যাচার একত্রিত করুন: Dispatchers.IO + SupervisorJob() + CoroutineExceptionHandler. এটি নির্দিষ্ট ডিসপ্যাচার, ত্রুটি হ্যান্ডলিং এবং বিচ্ছিন্ন Job শ্রেণিবিন্যাস সহ একটি CoroutineContext তৈরি করে।
সচরাচর জিজ্ঞাসিত প্রশ্ন
Dispatchers.IO I/O-bound অপারেশনের (I/O-র জন্য অপেক্ষা) জন্য 64 থ্রেড পর্যন্ত একটি পুল ব্যবহার করে, যখন Dispatchers.Default কম্পিউটেশনাল কাজের জন্য CPU কোরের সংখ্যার উপর ভিত্তি করে একটি পুল ব্যবহার করে। যখন থ্রেড দুষ্প্রাপ্য হয়, উভয় পুল একে অপরের সাথে থ্রেড ভাগ করতে পারে।
হ্যাঁ, একক-থ্রেডের জন্য newSingleThreadContext() বা ফিক্সড পুলের জন্য newFixedThreadPoolContext() ব্যবহার করুন। প্রোডাকশনের জন্য, বিদ্যমান ডিসপ্যাচারের উপর ভিত্তি করে limitedParallelism() ব্যবহার করুন — এটি নতুন পুল তৈরি করার চেয়ে বেশি কার্যকর।
যদি Dispatchers.Main উপলব্ধ না থাকে (যেমন, JUnit পরীক্ষা বা ব্যাকগ্রাউন্ড সার্ভিসে), তাহলে একটি IllegalStateException নিক্ষেপ করা হয়। পরীক্ষার জন্য TestCoroutineDispatcher এবং ব্যাকগ্রাউন্ড সার্ভিসের জন্য Dispatchers.IO বা Default ব্যবহার করুন।
Dispatchers.IO.limitedParallelism(N) ব্যবহার করুন, যেখানে N সমান্তরাল থ্রেডের সর্বোচ্চ সংখ্যা। এটি বাল্ক অনুরোধের সময় পুল শেষ হয়ে যাওয়া প্রতিরোধ করে এবং নিয়ন্ত্রিত সমান্তরালতা প্রদান করে।
Dispatchers.Unconfined মধ্যবর্তী অপারেশনের জন্য উপযুক্ত: অন্য ডিসপ্যাচারে পাস করার আগে হালকা ডেটা রূপান্তর, পরীক্ষার পরিস্থিতি। প্রোডাকশন Android কোডে, স্থগিত করার পরে অনির্ধারিত সম্পাদন থ্রেডের কারণে এটি সুপারিশ করা হয় না।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন