withContext: এটি কী, কনটেক্স্ট সুইচিং এবং করুটিনে কাজ

লেখক: IT Sectr প্রকাশিত: 2026-06-22 পড়ার সময়: 9 মিনিট

withContext — একটি করুটিনের ভিতরে এক্সিকিউশন কনটেক্স্ট পরিবর্তনকারী ফাংশন যা কোডের নির্দিষ্ট ব্লকের জন্য অস্থায়ীভাবে থ্রেড বা ডিসপ্যাচার পরিবর্তন করে এবং ফলাফল মূল কনটেক্স্টে ফিরিয়ে দেয়। JetBrains, 2025 অনুসারে, withContext নেটওয়ার্ক রিকোয়েস্ট এবং ডিস্ক অপারেশনের জন্য সবচেয়ে বেশি ব্যবহৃত করুটিন টুলগুলির মধ্যে একটি। ফাংশনটি গ্যারান্টি দেয় যে ব্লক শেষ হওয়ার পরে করুটিন মূল ডিসপ্যাচারে এক্সিকিউশন চালিয়ে যায়, যা আকস্মিক থ্রেড-সুরক্ষা ত্রুটিগুলি প্রতিরোধ করে।

মূল পয়েন্ট

  • withContext — একটি সাসপেন্ডিং ফাংশন যা প্রদত্ত কোড ব্লকের জন্য CoroutineContext পরিবর্তন করে এবং ফলাফল ফেরত দেয়
  • Dispatchers.IO — নেটওয়ার্ক এবং ডিস্ক অপারেশনের জন্য ব্যাকগ্রাউন্ড থ্রেডে সুইচ করার সাধারণ আর্গুমেন্ট
  • Dispatchers.Main — মূল কনটেক্সট যেখানে withContext ব্লক শেষ হওয়ার পরে স্বয়ংক্রিয়ভাবে এক্সিকিউশন ফিরিয়ে আনে
  • সিকোয়েন্সিয়াল কল — withContext কোড সিকোয়েন্সিয়ালভাবে এক্সিকিউট করে, launch এবং async এর বিপরীতে, যা অপারেশনের ক্রম নিয়ন্ত্রণ সহজ করে
  • Val ফলাফল — withContext ল্যাম্বডার শেষ লাইনে return এর মাধ্যমে সরাসরি মান ফেরত দেয়, await বা join ছাড়াই

Kotlin এ withContext কী?

withContext kotlinx.coroutines প্যাকেজ থেকে একটি সাসপেন্ডিং ফাংশন যা কোডের প্রদত্ত ব্লককে একটি নির্দিষ্ট CoroutineContext এ এক্সিকিউট করে এবং ফলাফল মূল কনটেক্সটে ফেরত দেয়। ফাংশনের সিগনেচারটি এরকম:

kotlin
suspend fun  withContext(
    context: CoroutineContext,
    block: suspend CoroutineScope.() -> T
): T

context প্যারামিটার যেকোনো CoroutineContext গ্রহণ করে — সাধারণত স্ট্যান্ডার্ড Dispatchers.IO, Dispatchers.Default বা Dispatchers.Main এর একটি। ব্লকটি সেই কনটেক্সটে এক্সিকিউট হয়, এবং ফলাফল where withContext কল করা হয়েছিল সেখানে ফেরত দেওয়া হয়।

মূল বৈশিষ্ট্য: স্বয়ংক্রিয় প্রত্যাবর্তন

ল্যাম্বডা শেষ হওয়ার পরে, withContext নিশ্চিতভাবে এক্সিকিউশন মূল ডিসপ্যাচারে ফিরিয়ে আনে। এর মানে ডেভেলপারকে ব্যাকগ্রাউন্ড অপারেশনের পরে ম্যানুয়ালি withContext(Dispatchers.Main) কল করতে হবে না — প্রত্যাবর্তন স্বয়ংক্রিয়ভাবে ঘটে। এই আচরণ Kotlin Coroutines স্পেসিফিকেশনে সংস্করণ 1.3 থেকে নথিভুক্ত।

withContext কোথায় ব্যবহৃত হয়

Android ডেভেলপমেন্ট হলো withContext ব্যবহারের প্রধান ক্ষেত্র। একটি সাধারণ পরিস্থিতি: ViewModel প্রধান থ্রেডে একটি করুটিন শুরু করে, ভিতরে নেটওয়ার্ক রিকোয়েস্টের জন্য withContext(Dispatchers.IO) কল করে, এবং Main এ স্বয়ংক্রিয় প্রত্যাবর্তনের পরে ফলাফল UI আপডেট করতে ব্যবহৃত হয়। এই পদ্ধতি MVVM আর্কিটেকচারের ভিত্তি এবং Google এর অফিসিয়াল করুটিন গাইডে সুপারিশকৃত।

withContext কীভাবে কাজ করে: ডিসপ্যাচার সুইচিং

withContext বুঝতে, আপনাকে CoroutineContext এবং এর মূল উপাদান — ডিসপ্যাচার বুঝতে হবে। প্রতিটি করুটিনের কনটেক্স্ট এলিমেন্টের একটি সেট থাকে, যার মধ্যে ডিসপ্যাচার নির্ধারণ করে কোন থ্রেড বা থ্রেড পুলে কোড চলে।

withContext এর জন্য স্ট্যান্ডার্ড ডিসপ্যাচার

ডিসপ্যাচারউদ্দেশ্যপুল আকার
Dispatchers.Mainপ্রধান UI থ্রেড (Android, JavaFX, Swing)1 (প্রধান থ্রেড)
Dispatchers.IOডিস্ক এবং নেটওয়ার্ক অপারেশন64 থ্রেড (সীমা বাড়ে)
Dispatchers.DefaultCPU-নিবিড় গণনাmax(2, কোর সংখ্যা)
Dispatchers.Unconfinedকোনো নির্দিষ্ট থ্রেড নেইঅসীম

এটা বোঝা গুরুত্বপূর্ণ যে withContext একটি নতুন করুটিন তৈরি করে না — এটি কেবল বিদ্যমান করুটিনের কনটেক্স্ট পরিবর্তন করে। এটি launch এবং async থেকে মূল পার্থক্য, যারা নতুন করুটিন তৈরি করে। withContext এর অভ্যন্তরীণ বাস্তবায়ন অপ্টিমাইজ করা: যদি অনুরোধকৃত কনটেক্স্ট বর্তমানের সাথে মেলে, কোনো সুইচিং ঘটে না — ফাংশনটি একই ডিসপ্যাচারে এক্সিকিউট হয়।

কখন withContext থ্রেড পরিবর্তন করে না

Dispatchers.Main withContext(Dispatchers.Main) এর ভিতরে পরিবর্তন ঘটায় না — Kotlin Coroutines কনটেক্স্টের অভিন্নতা চিনতে পারে এবং অপ্রয়োজনীয় অপারেশন এড়িয়ে যায়। একইভাবে, withContext(Dispatchers.Default) ইতিমধ্যে Default এ চলমান করুটিনের ভিতরে কোনো ওভারহেড তৈরি করে না। এই অপ্টিমাইজেশন ContinuationInterceptor এ বাস্তবায়িত।

withContext বনাম launch এবং async: কখন কী বেছে নেবেন

নতুনরা প্রায়ই withContext কে launch এবং async এর সাথে গুলিয়ে ফেলে, যেহেতু তিনটি ফাংশনই করুটিন এবং কনটেক্সট নিয়ে কাজ করে। তবে তাদের উদ্দেশ্য মৌলিকভাবে ভিন্ন।

তিনটি ফাংশনের তুলনা

বৈশিষ্ট্যwithContextlaunchasync
নতুন করুটিন তৈরি করেনাহ্যাঁহ্যাঁ
ফলাফল ফেরত দেয়হ্যাঁ (T সরাসরি)না (Job)হ্যাঁ (Deferred<T>)
এক্সিকিউশনসিকোয়েন্সিয়ালসমান্তরালসমান্তরাল
ফলাফলের অপেক্ষাস্বয়ংক্রিয়join()await()
সাধারণ ব্যবহার-ক্ষেত্রডিসপ্যাচার পরিবর্তনফায়ার-এন্ড-ফরগেটসমান্তরাল গণনা

নির্বাচনের নিয়ম

যদি আপনার ব্যাকগ্রাউন্ড থ্রেডে একটি অপারেশন এক্সিকিউট করতে এবং ফলাফল পেতে হয় — withContext ব্যবহার করুন। যদি আপনার একাধিক স্বাধীন অপারেশন সমান্তরালে চালানোর প্রয়োজন হয় — await সহ async ব্যবহার করুন। যদি ফলাফলের প্রয়োজন না হয় (লগিং, ক্যাশ লেখা) — launch ব্যবহার করুন। Google Android আর্কিটেকচারে Repository স্তরের জন্য withContext কে পছন্দের টুল হিসেবে সুপারিশ করে।

withContext সহ কোড উদাহরণ

আসুন Kotlin Android অ্যাপ্লিকেশনে withContext ব্যবহারের তিনটি ব্যবহারিক পরিস্থিতি দেখি। প্রতিটি উদাহরণ একটি নির্দিষ্ট কাজ এবং সঠিক প্যাটার্ন প্রদর্শন করে।

উদাহরণ 1: Repository এ নেটওয়ার্ক রিকোয়েস্ট

ViewModel Main এ করুটিন থেকে একটি রিপোজিটরি মেথড কল করে। ভিতরে, withContext(Dispatchers.IO) HTTP রিকোয়েস্ট সম্পাদন করে, এবং ফলাফল স্বয়ংক্রিয়ভাবে ফেরত আসে:

kotlin
class UserRepository(
    private val api: UserApi
) {
    suspend fun getUser(id: String): User {
        return withContext(Dispatchers.IO) {
            api.fetchUser(id)
        }
    }
}

ViewModel এ করুটিন getUser কে যেকোনো সাধারণ সাসপেন্ডিং ফাংশনের মতো কল করে — ডিসপ্যাচার স্পষ্টভাবে উল্লেখ না করেই। withContext থ্রেড পরিবর্তনের বিবরণ লুকিয়ে রাখে।

উদাহরণ 2: দুটি সিকোয়েন্সিয়াল ব্যাকগ্রাউন্ড অপারেশন

যখন আপনি একের পর এক একাধিক IO অপারেশন করতে চান, withContext সেগুলিকে একটি ব্লকে একত্রিত করে। এটি প্রতিটি অপারেশনকে আলাদা withContext এ মোড়ানোর চেয়ে বেশি কার্যকর:

kotlin
suspend fun loadUserProfile(id: String): Profile {
    return withContext(Dispatchers.IO) {
        val user = api.fetchUser(id)
        val posts = api.fetchPosts(id)
        Profile(user, posts)
    }
}

দুটি অপারেশনই Dispatchers.IO এ চলে, এবং Profile ফলাফল অপ্রয়োজনীয় কনটেক্স্ট পরিবর্তন ছাড়াই তৈরি এবং ফেরত দেওয়া হয়। যদি অপারেশনগুলি স্বাধীন হয়, তবে সমান্তরাল এক্সিকিউশনের জন্য async ব্যবহার করা ভাল।

উদাহরণ 3: NonCancellable সহ মিশ্র কনটেক্সট

কিছু পরিস্থিতিতে, আপনাকে এমন কোড এক্সিকিউট করতে হবে যা বাতিল করা যায় না — উদাহরণস্বরূপ, স্ক্রিন বন্ধ করার সময় অবস্থা সংরক্ষণ। withContext + NonCancellable এর সংমিশ্রণ এই কাজটি সমাধান করে:

kotlin
withContext(Dispatchers.IO + NonCancellable) {
    cache.saveState(state)
    analytics.logEvent("state_saved")
}

অপারেটর + দুটি কনটেক্স্ট এলিমেন্ট একত্রিত করে: IO ডিসপ্যাচার এবং NonCancellable ফ্ল্যাগ। ব্লকটি এক্সিকিউট হয় এমনকি যদি প্যারেন্ট করুটিন বাতিল করা হয় — ফাইনালাইজিং অপারেশনের জন্য উপযোগী।

পর্দার আড়ালে কী ঘটে: Continuation এবং অপটিমাইজেশন

withContext এর অভ্যন্তরীণ বাস্তবায়ন Continuation পদ্ধতির উপর ভিত্তি করে — Kotlin করুটিনের কেন্দ্রীয় অ্যাবস্ট্রাকশন। প্রতিটি সাসপেন্ড পয়েন্ট Continuation অবজেক্টে এক্সিকিউশন অবস্থা সংরক্ষণ করে, এবং withContext তার ব্যতিক্রম নয়।

withContext কীভাবে বাইটকোড স্তরে কনটেক্সট পরিবর্তন করে

Kotlin কম্পাইলার withContext কে kotlinx.coroutines থেকে withContext মেথড কলে অনুবাদ করে, যা অভ্যন্তরীণভাবে DispatchedContinuation এর একটি নতুন ইনস্ট্যান্স তৈরি করে। এই অবজেক্টটি মূল Continuation কে মোড়ানো করে এবং তার ডিসপ্যাচার প্রতিস্থাপন করে। যদি নতুন ডিসপ্যাচার বর্তমান থেকে ভিন্ন হয়, এক্সিকিউশন স্থগিত হয়, ব্লকটি সংশ্লিষ্ট থ্রেড পুলে পাঠানো হয়, এবং সম্পূর্ণ হওয়ার পরে — মূল কনটেক্সট দিয়ে পুনরায় শুরু হয়।

অপ্টিমাইজেশন: কনটেক্সট মিললে ফাস্ট-পাথ

যখন withContext একই ডিসপ্যাচারের সাথে কল করা হয় যাতে করুটিন ইতিমধ্যে চলছে, Kotlin ফাস্ট-পাথ (fast-path) সক্রিয় করে: ব্লকটি সিঙ্ক্রোনাসভাবে এক্সিকিউট হয়, DispatchedContinuation তৈরি না করে এবং থ্রেড পুলে না পাঠিয়ে। এটি withContext কে একই কনটেক্সট সহ পুনরাবৃত্ত কলের জন্য কার্যত বিনামূল্যে করে তোলে। JetBrains বেঞ্চমার্ক (kotlinx.coroutines 1.8) অনুসারে, ফাস্ট-পাথ 0.1 µs এর কমে সম্পন্ন হয়।

কার্যকারিতা বিবেচনা

withContext এর প্রতিটি কল ভিন্ন ডিসপ্যাচারের সাথে একটি নতুন DispatchedContinuation তৈরি করে এবং থ্রেড পরিবর্তনের প্রয়োজন — এতে লোডের উপর নির্ভর করে 1 থেকে 5 µs সময় লাগে। বেশিরভাগ অ্যাপ্লিকেশনের জন্য এই বিলম্ব অলক্ষিত, তবে হাজার হাজার পুনরাবৃত্তি সহ লুপের ভিতরে, একটি withContext ব্লকে অপারেশন একত্রিত করা মূল্যবান।

withContext ব্যবহার করার সময় সাধারণ ভুল

অভিজ্ঞ ডেভেলপাররাও withContext নিয়ে কাজ করার সময় ভুল করেন। আসুন চারটি সবচেয়ে সাধারণ সমস্যা এবং সেগুলি প্রতিরোধের উপায় দেখি।

ভুল 1: অপ্রয়োজনীয় নেস্টেড withContext

ডেভেলপাররা প্রায়ই প্রতিটি লাইনকে আলাদা withContext এ মোড়ান, অপারেশনগুলি একটি ব্লকে একত্রিত করার পরিবর্তে। ভিন্ন ডিসপ্যাচারের সাথে প্রতিটি অতিরিক্ত কল ওভারহেড তৈরি করে।

সঠিক: সিকোয়েন্সিয়াল IO অপারেশনগুলি একটি withContext(Dispatchers.IO) { ... } এ একত্রিত করুন। যদি কিছু অপারেশন CPU-নিবিড় হয় — একই ব্লকের ভিতরে withContext(Dispatchers.Default) ব্যবহার করুন।

ভুল 2: সমান্তরাল কাজের জন্য async এর পরিবর্তে withContext ব্যবহার

withContext কোড সিকোয়েন্সিয়ালভাবে এক্সিকিউট করে। যদি দুটি স্বাধীন নেটওয়ার্ক রিকোয়েস্ট একটি withContext এ মোড়ানো হয়, তারা একের পর এক চলবে। সমান্তরালতার জন্য, async + await ব্যবহার করুন।

kotlin
// সিকোয়েন্সিয়াল — ধীর
withContext(Dispatchers.IO) {
    val a = api.fetchA()
    val b = api.fetchB()
}

// সমান্তরাল — দ্রুত
coroutineScope {
    val a = async { api.fetchA() }
    val b = async { api.fetchB() }
    println("${a.await()} ${b.await()}")
}

ভুল 3: গুরুত্বপূর্ণ অপারেশনের জন্য NonCancellable ভুলে যাওয়া

যদি withContext চলাকালীন একটি করুটিন বাতিল করা হয়, Dispatchers.IO তে ব্লকটিও বাধাগ্রস্ত হয়। যে অপারেশনগুলি যেকোনো মূল্যে সম্পন্ন হতে হবে (ডেটাবেস লেখা, অ্যানালিটিক্স পাঠানো) তাদের জন্য withContext কে NonCancellable এর সাথে একত্রিত করুন।

ভুল 4: IO ব্লকের ভিতরে UI অবস্থা আপডেট করা

কখনই withContext(Dispatchers.IO) এর ভিতরে View কম্পোনেন্ট আপডেট করবেন না। withContext পুরো ব্লক শেষ না হওয়া পর্যন্ত Main এ ফেরত আসে না। withContext এর ক্লোজিং ব্রেসের পরে UI আপডেট রাখুন — তখন করুটিন ইতিমধ্যে প্রধান থ্রেডে থাকবে।

প্রায়শই জিজ্ঞাসিত প্রশ্ন

withContext runBlocking থেকে কীভাবে আলাদা?

withContext একটি সাসপেন্ডিং ফাংশন যা থ্রেড ব্লক করে না, বরং বিদ্যমান করুটিনের ভিতরে কনটেক্সট পরিবর্তন করে। runBlocking করুটিন এবং সাধারণ কোডের মধ্যে একটি সেতু যা সম্পন্ন না হওয়া পর্যন্ত বর্তমান থ্রেড ব্লক করে। withContext UI থ্রেডের জন্য নিরাপদ, runBlocking নয়।

withContext কি suspend ছাড়া ব্যবহার করা যায়?

না, withContext একটি suspend ফাংশন, তাই এটি শুধুমাত্র অন্য suspend ফাংশন বা করুটিন (launch/async) থেকে কল করা যায়। সাধারণ ফাংশন থেকে withContext কল করা যায় না — এর জন্য runBlocking বা CoroutineScope প্রয়োজন।

withContext এ একই ডিসপ্যাচার পাস করলে কী হয়?

Kotlin ফাস্ট-পাথ (fast-path) সক্রিয় করে — ব্লকটি একই থ্রেডে সিঙ্ক্রোনাসভাবে পরিবর্তন ছাড়াই এক্সিকিউট হয়। ওভারহেড 0.1 µs এর কম। এটি কোনো ত্রুটি নয়, তবে এই ধরনের কল অপ্রয়োজনীয় — withContext ছাড়াই কোড এক্সিকিউট করা ভাল।

withContext ব্যতিক্রম (exceptions) সাথে কীভাবে কাজ করে?

withContext এর ভিতরে ব্যতিক্রম সাধারণ কোডের মতোই প্রচারিত হয় — try-catch এর মাধ্যমে। যদি ব্লকটি একটি ব্যতিক্রম ছুঁড়ে, এটি প্যারেন্ট করুটিনে প্রচারিত হয় এবং যদি হ্যান্ডেল না করা হয় তবে এটি বাতিল করে দেয়। withContext এর ভিতরে বা তার চারপাশে try-catch ব্যবহার করুন।

withContext কি একটি নতুন করুটিন তৈরি করে নাকি?

না, withContext একটি নতুন করুটিন তৈরি করে না। এটি বিদ্যমান করুটিন ব্যবহার করে তবে অস্থায়ীভাবে তার কনটেক্সট পরিবর্তন করে। এটি একে launch এবং async থেকে আলাদা করে, যারা চাইল্ড করুটিন তৈরি করে। এই আচরণ kotlinx.coroutines সোর্স কোড দ্বারা নিশ্চিত।

সারসংক্ষেপ

  • withContext — বিদ্যমান করুটিনের ভিতরে CoroutineContext পরিবর্তনের জন্য একটি suspend ফাংশন যা মূল কনটেক্সটে স্বয়ংক্রিয় প্রত্যাবর্তন করে
  • Dispatchers.IO — withContext এর ভিতরে নেটওয়ার্ক রিকোয়েস্ট এবং ডিস্ক অপারেশনের জন্য প্রধান ডিসপ্যাচার
  • ফাস্ট-পাথ (Fast-path) — একটি Kotlin অপ্টিমাইজেশন যেখানে withContext একই ডিসপ্যাচারের সাথে ওভারহেড ছাড়াই সিঙ্ক্রোনাসভাবে এক্সিকিউট হয়
  • সমান্তরাল কাজ async/await প্রয়োজন, withContext নয় — withContext কোড সিকোয়েন্সিয়ালভাবে এক্সিকিউট করে
  • NonCancellable — withContext এর ভিতরে গুরুত্বপূর্ণ অপারেশনের জন্য একটি ফ্ল্যাগ যা করুটিন বাতিল হলে বাধাগ্রস্ত হওয়া উচিত নয়
  • Repository স্তর — Google নির্দেশিকা অনুসারে Android আর্কিটেকচারে withContext এর জন্য সুপারিশকৃত স্থান
  • Continuation — যে পদ্ধতির উপর Kotlin বাইটকোড স্তরে withContext এ কনটেক্স্ট পরিবর্তন ভিত্তিক

আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব

IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।

প্রকল্প নিয়ে আলোচনা করুন

আরও পড়ুন