Channel: এটি কী, চ্যানেলের প্রকার এবং Kotlin-এ করুটিন

লেখক: IT Sectr প্রকাশিত: 2026-03-17 পড়ার সময়: 8 মিনিট

Channel হল Kotlin Coroutines লাইব্রেরি থেকে একটি সিঙ্ক্রোনাইজেশন প্রিমিটিভ যা করুটিনের মধ্যে ডেটা স্থানান্তরের জন্য ব্যবহৃত হয়। Kotlin Documentation, 2025 অনুসারে, Channel suspend-ফাংশনের মাধ্যমে ব্লকিং পাঠানো সহ producer-consumer প্যাটার্ন বাস্তবায়ন করে। Channel Rendezvous, Buffered এবং Conflated মোড সমর্থন করে, যার প্রতিটি ওভারফ্লো হওয়ার সময় আচরণ নির্ধারণ করে।

মূল পয়েন্ট

  • Channel হল kotlinx.coroutines থেকে করুটিনের মধ্যে ডেটা ট্রান্সফার প্রিমিটিভ, যা producer-consumer প্যাটার্নের উপর ভিত্তি করে
  • Rendezvous Channel — বাফার ছাড়া: send() স্থগিত থাকে যতক্ষণ না receive() কল করা হয়
  • Buffered Channel — নির্দিষ্ট ক্ষমতার বাফার সহ, পূর্ণ হলে send() স্থগিত হয়
  • Conflated Channel — শুধুমাত্র সর্বশেষ মান সংরক্ষণ করে, ওভারফ্লো হলে পুরানো মান বাতিল হয়
  • Channel হট স্ট্রিম, callbackFlow এবং অ্যাক্টর মডেল তৈরির ভিত্তি

Kotlin-এ Channel কী?

Channel ধারণাগতভাবে Java-র BlockingQueue-এর মতো, তবে ব্লকিং put() এবং take()-এর পরিবর্তে suspend ফাংশন send() এবং receive() সহ। একজন Kotlin ডেভেলপার শেয়ার্ড মেমরির মাধ্যমে সিঙ্ক্রোনাইজেশন ছাড়াই করুটিনের মধ্যে ডেটা আদান-প্রদান সংগঠিত করতে Channel ব্যবহার করে। চ্যানেল অর্ডারকৃত ডেলিভারি নিশ্চিত করে — পাঠানোর ক্রম প্রাপ্তির ক্রমের সাথে মেলে।

চ্যানেল তৈরি করা

Channel তৈরি করতে ফ্যাক্টরি ফাংশন Channel<T>(capacity) কল করা হয়। প্যারামিটার capacity চ্যানেলের প্রকার নির্ধারণ করে: RENDEZVOUS (0), UNLIMITED (Int.MAX_VALUE), CONFLATED (-1) বা একটি নির্দিষ্ট সংখ্যা। উপাদানের প্রকার T জেনেরিকের মাধ্যমে নির্দিষ্ট করা হয়। close() এর মাধ্যমে চ্যানেল বন্ধ করা সংকেত দেয় যে নতুন কোনো উপাদান আসবে না।

Send এবং Receive

send(value) একটি suspend ফাংশন যা চ্যানেল পূর্ণ হলে প্রেরণকারী করুটিনকে স্থগিত করে। receive() একটি suspend ফাংশন যা চ্যানেল খালি হলে গ্রহীতাকে স্থগিত করে। বিকল্প trySend() এবং tryReceive() হল নন-ব্লকিং সংস্করণ যা অপারেশন সম্ভব না হলে Boolean বা null ফেরত দেয়। এগুলি নন-suspend প্রসঙ্গে উপযোগী।

kotlinx.coroutines-এ Channel-এর প্রকার

Kotlin বাফার ক্ষমতার মাধ্যমে Channel-এর চারটি ভ্যারিয়েন্ট প্রদান করে: Rendezvous (ক্ষমতা 0), Buffered (ক্ষমতা N), Conflated (ক্ষমতা 1, ওভাররাইট) এবং Unlimited (ক্ষমতা Int.MAX_VALUE)। প্রতিটি প্রকার তার নিজস্ব কাজ সমাধান করে, কঠোর সিঙ্ক্রোনাইজেশন থেকে ব্যাপক ডেটা বাফারিং পর্যন্ত।

Rendezvous Channel সবচেয়ে কঠোর: send() ব্লক থাকে যতক্ষণ না অন্য করুটিনে receive() কল করা হয়। সারমর্মে, এটি দুটি করুটিনের মিলন বিন্দু। কঠোর হ্যান্ডশেকের জন্য আদর্শ যখন প্রেরককে গ্রহীতা উপাদান প্রক্রিয়া করার জন্য অপেক্ষা করতে হবে। ডেটা ক্ষতি বাদ দেওয়া হয় — send সম্পূর্ণ হয় না যতক্ষণ না receive সম্পাদিত হয়।

Conflated Channel শুধুমাত্র সর্বশেষ পাঠানো মান সংরক্ষণ করে। যদি প্রেরক গ্রহীতা পুরানো মান নেওয়ার আগে নতুন উপাদান রাখে, তবে পুরানোটি বাতিল হয়। Conflated Channel UI অবস্থার জন্য উপযোগী: যদি ব্যবহারকারী দ্রুত স্লাইডার পরিবর্তন করে, মধ্যবর্তী মানগুলি বাতিল করা যেতে পারে এবং শুধুমাত্র সর্বশেষটি প্রক্রিয়া করা যেতে পারে।

চ্যানেলে উৎপাদক-ভোক্তা

Channel-এ ক্লাসিক উৎপাদক-ভোক্তা প্যাটার্ন সমান্তরাল করুটিনের মাধ্যমে বাস্তবায়িত হয়। উৎপাদক লুপে send(value) কল করে, ভোক্তা receive(value) কল করে। উৎপাদক এবং ভোক্তা ভিন্ন Dispatchers-এ কাজ করতে পারে: উৎপাদক Dispatchers.IO-তে, ভোক্তা Dispatchers.Main-এ। Channel Lock বা synchronized ছাড়াই স্বয়ংক্রিয়ভাবে অ্যাক্সেস সিঙ্ক্রোনাইজ করে।

Fan-out — একটি চ্যানেলে একাধিক ভোক্তা। প্রতিটি উপাদান ঠিক একজন ভোক্তার কাছে যায় (round-robin বিতরণ)। Fan-in — একাধিক উৎপাদক একটি চ্যানেলে লেখে। প্রেরণকারী করুটিনগুলি পাঠানোর জন্য প্রতিযোগিতা করে, তবে উপাদানের ক্রম সংরক্ষিত থাকে। উভয় পরিস্থিতিতে অতিরিক্ত সিঙ্ক্রোনাইজেশনের প্রয়োজন নেই।

Produce একটি করুটিন বিল্ডার যা স্বয়ংক্রিয় বন্ধের সাথে একটি চ্যানেল তৈরি করে। ফাংশন produce { } একটি ReceiveChannel ফেরত দেয় — ভোক্তার জন্য শুধুমাত্র-পঠনযোগ্য চ্যানেল। বিল্ডারের ভিতরে send() ডেটা পাঠায়, এবং ব্লক সম্পূর্ণ হলে বা ব্যতিক্রম ঘটলে চ্যানেল স্বয়ংক্রিয়ভাবে বন্ধ হয়ে যায়, লিক প্রতিরোধ করে।

Select এবং মাল্টিপ্লেক্সিং

kotlinx.coroutines লাইব্রেরি select প্রদান করে — একটি এক্সপ্রেশন যা একাধিক বিকল্পের মধ্যে প্রথম সম্পন্ন চ্যানেলের জন্য অপেক্ষা করে। Select একাধিক চ্যানেল মাল্টিপ্লেক্স করার অনুমতি দেয়: উদাহরণস্বরূপ, দুটি উৎস থেকে ডেটার জন্য অপেক্ষা করা এবং প্রথম যে উত্তর দেয় তা প্রক্রিয়া করা। সিনট্যাক্স — select<T> { channel1.onReceive { } channel2.onReceive { } }। এটি Rx-এ amb অপারেটরের বিকল্প।

Channel কোড উদাহরণ

প্রথম উদাহরণটি একটি সরল Rendezvous Channel যেখানে প্রেরক প্রাপ্তির জন্য অপেক্ষা করে:

kotlin
val channel = Channel<String>()

scope.launch {
    channel.send("Hello")
    println("পাঠানো হয়েছে")
}

scope.launch {
    val msg = channel.receive()
    println("গৃহীত: $msg")
}

দ্বিতীয় উদাহরণ — একটি চ্যানেলে একাধিক ভোক্তা (fan-out):

kotlin
val channel = Channel<Int>(Channel.UNLIMITED)

scope.launch {
    for (x in 1..10) channel.send(x)
    channel.close()
}

repeat(2) { id ->
    scope.launch {
        for (msg in channel) {
            println("Consumer #$id: $msg")
        }
    }
}

তৃতীয় উদাহরণ — ত্রুটি পরিচালনার সাথে produce বিল্ডার ব্যবহার:

kotlin
val source = produce {
    for (i in 1..5) {
        delay(200)
        send(i)
    }
}

scope.launch {
    source
        .consumeAsFlow()
        .catch { println("ত্রুটি: $it") }
        .collect { println("উপাদান: $it") }
}

Channel বনাম Flow

Channel একটি হট প্রিমিটিভ: ডেটা সাবস্ক্রাইবারদের থেকে স্বাধীনভাবে নির্গত হয়। Flow হল কোল্ড: সাবস্ক্রিপশনে ডেটা উৎপন্ন হয়। Channel প্রতিটি উপাদানের একজন ভোক্তার কাছে গ্যারান্টিকৃত ডেলিভারি (fan-out) সহ একাধিক উৎপাদক এবং ভোক্তা সমর্থন করে। Flow একাধিক স্বাধীন উৎপাদকের জন্য ডিজাইন করা হয়নি।

Channel ব্যাকপ্রেশার ব্যবস্থাপনার জন্য কনফিগারযোগ্য ক্ষমতার বাফার এবং suspend ফাংশন send/receive ব্যবহার করে। Flow করুটিনের মাধ্যমে স্বয়ংক্রিয় ব্যাকপ্রেশার সহ suspend মেকানিজম collect ব্যবহার করে। Channel নির্দিষ্ট পরিস্থিতির জন্য একটি নিম্ন-স্তরের টুল: কলব্যাক রূপান্তর, অ্যাক্টর মডেল, একাধিক প্রেরক সহ কাজের কিউ।

Android-এ দৈনন্দিন পরিস্থিতির জন্য (UI অবস্থা, DB থেকে রিয়েক্টিভ স্ট্রিম) Google Channel-এর পরিবর্তে Flow সুপারিশ করে। Channel ব্যবহার করা উচিত যখন সঠিক বাফার নিয়ন্ত্রণ সহ করুটিনের মধ্যে হট ডেটা আদান-প্রদানের প্রয়োজন হয়, বা callbackFlow-এর মাধ্যমে কলব্যাক ইন্টারফেস রূপান্তর করার সময়, যার অভ্যন্তরীণ বাস্তবায়ন Channel ব্যবহার করে।

একটি গুরুত্বপূর্ণ ব্যবহারিক উদাহরণ: WebSocket ক্লায়েন্ট বাস্তবায়ন করার সময়, Channel একটি করুটিন থেকে বার্তা লেখার এবং অন্যটি থেকে পড়ার অনুমতি দেয় এই গ্যারান্টি সহ যে প্রতিটি বার্তা ঠিক একবার প্রক্রিয়া করা হবে। Flow এই কাজের জন্য উপযুক্ত নয় কারণ এটি কোল্ড এবং একাধিক উৎপাদক সমর্থন করে না। UNLIMITED ক্ষমতার Channel নিশ্চিত করে যে অস্থায়ী ভোক্তা বিলম্বের সময় আগত বার্তা হারিয়ে না যায়।

চ্যানেল লাইফসাইকেল ব্যবস্থাপনা Channel-এর সাথে কাজের একটি গুরুত্বপূর্ণ অংশ। যখন সমস্ত ডেটা পাঠানো হয়ে যায় তখন চ্যানেলটি বন্ধ করতে হবে যাতে ভোক্তা পুনরাবৃত্তি শেষ করতে পারে। channel.close() কল করা সংকেত দেয় যে নতুন কোনো উপাদান আসবে না। ভোক্তা for (item in channel) এর মাধ্যমে পুনরাবৃত্তি করতে পারে — close() এবং বাফার খালি হওয়ার পরে লুপ স্বয়ংক্রিয়ভাবে শেষ হবে। বিকল্পভাবে ভোক্তা ClosedReceiveChannelException পরিচালনা সহ লুপে receive() কল করতে পারে।

Channel Android-এ নির্ভরতা ছাড়াই EventBus বাস্তবায়নের জন্য সক্রিয়ভাবে ব্যবহৃত হয়: Broadcast কৌশল সহ একটি গ্লোবাল Channel<Event> অ্যাপ্লিকেশনের যেকোনো বিন্দু থেকে ইভেন্ট পাঠানোর অনুমতি দেয়। LiveData-ভিত্তিক বাসের বিপরীতে, Channel লাইফসাইকেলের সাথে আবদ্ধ নয় এবং স্ক্রিনের মধ্যে স্থানান্তরের সময় পরিষ্কারের প্রয়োজন নেই। ViewModel থেকে send() এবং Activity/Fragment-এ lifecycleScope-এর মাধ্যমে receive() Event ক্লাস ছাড়াই টাইপ-নিরাপদ যোগাযোগ প্রদান করে। Channel-এ একাধিক ভোক্তা লোড বিতরণ করে — প্রতিটি উপাদান একবার প্রক্রিয়া করা হয়, যা বিভিন্ন সাবস্ক্রাইবারে একটি একক ইভেন্টের ডুপ্লিকেট প্রক্রিয়াকরণ প্রতিরোধ করে।

অ্যাক্টর সিস্টেমে Channel মেইলবক্স — অ্যাক্টরের জন্য বার্তা কিউ — বাস্তবায়নের ভিত্তি হিসাবে কাজ করে। একটি অ্যাক্টর হল একটি করুটিন যা লুপে Channel থেকে বার্তা পড়ে এবং সেগুলিকে ক্রমিকভাবে প্রক্রিয়া করে। এই পদ্ধতি নিশ্চিত করে যে প্রতিটি বার্তা পাঠানোর ক্রমে প্রক্রিয়া করা হয়, ডেটা রেস ছাড়াই। Kotlin-এ একটি প্রকার হিসাবে বিল্ট-ইন অ্যাক্টর নেই (Akka-র বিপরীতে), তবে Channel + launch একটি হালকা প্রতিস্থাপন।

দ্বিমুখী আদান-প্রদানের জন্য চ্যানেল জোড়া ব্যবহার করা হয়: একটি চ্যানেল ক্লায়েন্ট থেকে সার্ভারে অনুরোধের জন্য, দ্বিতীয়টি সার্ভার থেকে ক্লায়েন্টে প্রতিক্রিয়ার জন্য। উদাহরণস্বরূপ, মাল্টিথ্রেডেড অ্যাপ্লিকেশনে Pipe বাস্তবায়ন করার সময়: উৎপাদক OutputChannel-এ লেখে, ভোক্তা InputChannel থেকে পড়ে। suspend ফাংশন send এবং receive গ্যারান্টি দেয় যে উৎপাদক-ভোক্তা কল স্ট্যাক ওভারফ্লো করবে না, কারণ করুটিন ব্লক হওয়ার পরিবর্তে স্থগিত হয়। BUFFERED ক্ষমতার Channel অধিকাংশ পরিস্থিতির জন্য উপযুক্ত যেখানে উৎপাদক এবং ভোক্তার গতি প্রায় সমান। অসমমিত পরিস্থিতির জন্য UNLIMITED ব্যবহার করুন যাতে ভোক্তা ব্যস্ত থাকলে উৎপাদক স্থগিত না হয় — এটি ডেডলকের ঝুঁকি হ্রাস করে তবে মেমরি খরচ বাড়ায়।

Channel ক্ষমতা নির্বাচন

চ্যানেলের উপর আর্কিটেকচার ডিজাইন করার সময় capacity মনে রাখা গুরুত্বপূর্ণ: ক্ষমতার পছন্দ সরাসরি পিক লোডের অধীনে আচরণকে প্রভাবিত করে। BUFFERED(N) ক্ষমতার চ্যানেলগুলি একটি স্মুথিং বাফার হিসাবে কাজ করে: যদি ভোক্তা অস্থায়ীভাবে উৎপাদকের চেয়ে ধীর হয়, উপাদান জমা হয়। যদি ভোক্তার গড় গতি ধারাবাহিকভাবে উৎপাদকের চেয়ে কম হয়, বাফার পূর্ণ হবে এবং প্রেরণকারী করুটিন স্থগিত হবে — এটি স্বয়ংক্রিয় ব্যাকপ্রেশার যা মেমরি ওভারলোড থেকে রক্ষা করে।

Channel পর্যবেক্ষণ এবং ডিবাগিংয়ের জন্য kotlinx-coroutines-debug ব্যবহার করুন: ইউটিলিটি সক্রিয় করুটিনের সংখ্যা, তাদের চ্যানেলের অবস্থা (খোলা/বন্ধ, বাফারে উপাদানের সংখ্যা), এবং স্থগিত send/receive অপারেশনের কল স্ট্যাক দেখায়। Channel কে একটি লগিং প্রক্সিতেও মোড়ানো যেতে পারে: LoggingChannel<T> ক্লাস বাস্তব Channel-এ কল ডেলিগেট করে, send, receive এবং close অপারেশন লগ করে। এটি চ্যানেল লিক সনাক্ত করতে সাহায্য করে যখন close() কল করা হয়নি এবং ভোক্তা করুটিন চিরকাল নতুন উপাদানের জন্য অপেক্ষা করছে।

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

Channel BlockingQueue থেকে কীভাবে আলাদা?

Channel ব্লকিং put() এবং take()-এর পরিবর্তে suspend ফাংশন send() এবং receive() ব্যবহার করে। BlockingQueue-এর বিপরীতে, Channel ওভারফ্লো হলে থ্রেড ব্লক করে না — করুটিন স্থগিত হয়, অন্যান্য করুটিনের জন্য থ্রেড মুক্ত করে। Kotlin-এ দক্ষ থ্রেড ব্যবহারের জন্য এটি গুরুত্বপূর্ণ।

বন্ধ Channel-এ send() কল করলে কী হয়?

বন্ধ চ্যানেলে send() কল করলে ClosedSendChannelException নিক্ষেপ হয়। পাঠানোর আগে isClosedForSend পরীক্ষা করুন বা trySend() ব্যবহার করুন যা বন্ধ হলে false ফেরত দেয়। close() গ্যারান্টি দেয় যে ইতিমধ্যে পাঠানো উপাদান ব্যতিক্রম নিক্ষেপের আগে প্রাপ্ত হবে।

কখন Conflated Channel ব্যবহার করবেন?

Conflated Channel সেই ইভেন্টগুলির জন্য উপযোগী যেখানে শুধুমাত্র সর্বশেষ অবস্থা গুরুত্বপূর্ণ — প্রগ্রেস বার, স্লাইডার অবস্থান, স্পর্শ স্থানাঙ্ক। যদি ভোক্তা সমস্ত ইভেন্ট প্রক্রিয়া করতে না পারে, মধ্যবর্তীগুলি বাতিল হয় এবং সর্বশেষটি গ্যারান্টিকৃতভাবে প্রক্রিয়া করা হয়। Conflated Channel-এর capacity=-1।

কীভাবে একটি চ্যানেল বন্ধ করবেন এবং অবশিষ্ট উপাদান প্রক্রিয়া করবেন?

channel.close() কল করুন — চ্যানেলটি পাঠানোর জন্য বন্ধ হিসাবে চিহ্নিত হয়, তবে ইতিমধ্যে পাঠানো উপাদান receive()-এর মাধ্যমে পড়া চালিয়ে যায়। for (item in channel) দিয়ে পুনরাবৃত্তি বাফার খালি হওয়ার পরে স্বয়ংক্রিয়ভাবে শেষ হয়। isClosedForSend তাৎক্ষণিকভাবে true ফেরত দেয়, isClosedForReceive খালি হওয়ার পরে true ফেরত দেয়।

Channel কি Flow দিয়ে প্রতিস্থাপন করা যেতে পারে?

সবসময় নয়। Flow কোল্ড — একটি নির্গমন প্রতি collect। যদি একাধিক স্বাধীন উৎপাদকের একটি স্ট্রিমে লেখার প্রয়োজন হয়, Channel বাধ্যতামূলক। দুটি করুটিনের মধ্যে সরল ডেটা স্থানান্তরের জন্য Channel ব্যবহার করুন। ডেটা সহ রিয়েক্টিভ স্ট্রিমের জন্য Flow ব্যবহার করুন।

সারসংক্ষেপ

  • Channel করুটিনের মধ্যে ডেটা স্থানান্তরের জন্য একটি হট সিঙ্ক্রোনাইজেশন প্রিমিটিভ
  • Rendezvous — বাফার ছাড়া, send receive কল না হওয়া পর্যন্ত ব্লক থাকে
  • Buffered — নির্দিষ্ট ক্ষমতার বাফার সহ, পূর্ণ হলে send স্থগিত হয়
  • Conflated — শুধুমাত্র সর্বশেষ মান সংরক্ষণ করে, মধ্যবর্তীগুলি বাতিল হয়
  • Produce — স্বয়ংক্রিয় বন্ধের সাথে চ্যানেলের জন্য করুটিন বিল্ডার
  • Fan-out — একাধিক ভোক্তা round-robin-এর মাধ্যমে উপাদান বিতরণ করে
  • UI অবস্থার জন্য StateFlow ব্যবহার করুন, Channel হট কিউ এবং কলব্যাক রূপান্তরের জন্য

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

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

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

আরও পড়ুন