Concurrency in Go (কনকারেন্সি)
Go প্রোগ্রামিং ভাষায় concurrency বা কনকারেন্সি হল একাধিক কাজ একসাথে, পরস্পর লুকানো বা সমান্তরালভাবে পরিচালনা করার কৌশল। Go-তে কনকারেন্সি খুবই সহজ এবং কার্যকরীভাবে ব্যবহৃত হয়। Go-এর দুটি শক্তিশালী কনকারেন্সি ফিচার হলো goroutines এবং channels। এগুলি ব্যবহারের মাধ্যমে আপনি কার্যকরীভাবে একাধিক কাজ পরিচালনা করতে পারেন।
১. Goroutines (গোরাউটিনস)
Goroutines হল Go-তে কনকারেন্সি পরিচালনা করার অন্যতম গুরুত্বপূর্ণ উপাদান। একটি goroutine হলো একটি ফাংশন যা আলাদা থ্রেডে কার্যকরী হয়। Go-তে goroutines খুবই লাইটওয়েট এবং সিস্টেমের রিসোর্স কম খরচ করে। এটি মূলত অন্যান্য সিস্টেম থ্রেডের চেয়ে আরও দ্রুত এবং কমপ্লেক্স কোডিংয়ের প্রয়োজন ছাড়াই একাধিক কাজ পরিচালনা করতে সহায়তা করে।
১.১ Goroutine ডিফাইনেশন
Go-তে একটি নতুন goroutine চালু করার জন্য আপনি go কিওয়ার্ড ব্যবহার করতে পারেন, যা একটি ফাংশনকে আলাদা থ্রেডে চালাবে।
package main
import "fmt"
// সাধারণ ফাংশন
func printMessage(message string) {
fmt.Println(message)
}
func main() {
// নতুন goroutine তৈরি
go printMessage("Hello from Goroutine")
// Main ফাংশনে আরও কাজ করা
fmt.Println("Hello from Main")
}এখানে, go printMessage("Hello from Goroutine") লাইনটি printMessage ফাংশনকে একটি নতুন goroutine হিসেবে চালু করে। তবে, main ফাংশনের আউটপুটটি প্রথমে আসে কারণ main ফাংশনটি goroutine-এর আগে শেষ হতে পারে।
আউটপুট (সম্ভবত):
Hello from Main
Hello from Goroutineমনে রাখবেন: goroutines একটি asynchronous প্রক্রিয়া, তাই তাদের রানের অর্ডার পূর্বানুমান করা সম্ভব নয়।
২. Channels (চ্যানেলস)
Channels হল একটি ডেটা স্ট্রাকচার যা goroutines-এর মধ্যে ডেটা আদান-প্রদান করতে ব্যবহৃত হয়। এক বা একাধিক goroutine মধ্যে ডেটা ভাগাভাগি করতে চ্যানেল খুবই কার্যকরী। আপনি যখন একটি goroutine থেকে অন্য goroutine-এ ডেটা পাঠাতে চান, তখন আপনি একটি চ্যানেল ব্যবহার করবেন।
২.১ Channel ডিফাইনেশন এবং ব্যবহার
চ্যানেল ডিফাইন করতে make ফাংশন ব্যবহার করতে হয়। একটি চ্যানেল তৈরি করার পরে, আপনি সেটিতে ডেটা পাঠাতে এবং গ্রহণ করতে পারেন।
package main
import "fmt"
func sendData(ch chan string) {
ch <- "Hello from Goroutine" // Goroutine থেকে চ্যানেলে ডেটা পাঠানো
}
func main() {
ch := make(chan string) // চ্যানেল তৈরি করা
go sendData(ch) // একটি goroutine চালু করা
// চ্যানেল থেকে ডেটা গ্রহণ করা
msg := <-ch
fmt.Println(msg) // আউটপুট: Hello from Goroutine
}এখানে, sendData ফাংশনটি একটি goroutine হিসেবে চালু করা হয়েছে এবং এটি একটি চ্যানেলে ডেটা পাঠাচ্ছে। main ফাংশনটি সেই চ্যানেল থেকে ডেটা গ্রহণ করে এবং এটি প্রিন্ট করে।
আউটপুট:
Hello from Goroutine২.২ Buffered Channels
Go-তে আপনি buffered channels তৈরি করতে পারেন, যার মাধ্যমে চ্যানেলগুলিতে নির্দিষ্ট পরিমাণ ডেটা জমা রাখা সম্ভব হয়। একটি buffered channel এর ক্ষেত্রে, ডেটা পাঠানো হয় যতক্ষণ না চ্যানেলে প্রাপ্ত স্লট পূর্ণ হয়ে যায়।
package main
import "fmt"
func main() {
// Buffered channel তৈরি করা, যেটি 2টি স্লট ধারণ করতে পারে
ch := make(chan string, 2)
// চ্যানেলে ডেটা পাঠানো
ch <- "Message 1"
ch <- "Message 2"
// চ্যানেল থেকে ডেটা গ্রহণ করা
fmt.Println(<-ch) // আউটপুট: Message 1
fmt.Println(<-ch) // আউটপুট: Message 2
}এখানে, আমরা একটি buffered channel তৈরি করেছি যা দুটি স্লট ধারণ করতে সক্ষম। ডেটা পাঠানো এবং গ্রহণ করা হয় যথাযথভাবে।
৩. Synchronization (সিঙ্ক্রোনাইজেশন)
কনকারেন্সি ব্যবহারে synchronization খুবই গুরুত্বপূর্ণ। আপনি যখন একাধিক goroutines এর মধ্যে কাজ করতে চান, তখন আপনি সিঙ্ক্রোনাইজেশন নিশ্চিত করতে পারেন, যেমন WaitGroup ব্যবহার করে সমস্ত goroutines শেষ না হওয়া পর্যন্ত অপেক্ষা করা।
৩.১ WaitGroup ব্যবহার করা
sync.WaitGroup হল একটি Go প্যাকেজ যা goroutines সমন্বয় এবং সিঙ্ক্রোনাইজ করতে ব্যবহৃত হয়। এটি আপনাকে নিশ্চিত করতে সাহায্য করে যে সমস্ত goroutines কাজ শেষ করার পরেই মূল ফাংশন (main) শেষ হবে।
package main
import (
"fmt"
"sync"
)
func task(id int, wg *sync.WaitGroup) {
defer wg.Done() // goroutine কাজ শেষ হলে WaitGroup থেকে Done() কল করবে
fmt.Printf("Task %d is completed\n", id)
}
func main() {
var wg sync.WaitGroup
// 3টি goroutine চালু করা
for i := 1; i <= 3; i++ {
wg.Add(1) // WaitGroup এ 1টি কাজ যোগ করা
go task(i, &wg)
}
// সব goroutine শেষ না হওয়া পর্যন্ত অপেক্ষা করা
wg.Wait()
fmt.Println("All tasks are completed")
}এখানে, wg.Add(1) প্রতি goroutine শুরু করার আগে কল করা হয়, এবং wg.Done() প্রতিটি goroutine এর কাজ শেষ হলে কল করা হয়। wg.Wait() মূল ফাংশনে কল করা হয় যাতে নিশ্চিত হয় যে সমস্ত goroutines শেষ না হওয়া পর্যন্ত main ফাংশন শেষ হবে না।
আউটপুট:
Task 1 is completed
Task 2 is completed
Task 3 is completed
All tasks are completed৪. Select Statement (সিলেক্ট স্টেটমেন্ট)
Go-তে select স্টেটমেন্ট চ্যানেলগুলি থেকে ডেটা গ্রহণ করার জন্য ব্যবহৃত হয়। এটি একাধিক চ্যানেল থেকে ডেটা গ্রহণ করতে ব্যবহৃত হয়, এবং যখন যেকোনো একটি চ্যানেল থেকে ডেটা আসে, তখন সেটি নির্বাচন করা হয়।
package main
import "fmt"
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() { ch1 <- "Hello from ch1" }()
go func() { ch2 <- "Hello from ch2" }()
// Select statement দিয়ে চ্যানেল থেকে ডেটা গ্রহণ
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
}এখানে, select স্টেটমেন্ট দুটি চ্যানেল থেকে ডেটা গ্রহণ করে, এবং যেকোনো একটি চ্যানেল থেকে ডেটা আসলেই সেটি প্রিন্ট করা হয়।
সারসংক্ষেপ
- Goroutines: Go-তে কনকারেন্সি চালানোর জন্য goroutines ব্যবহার করা হয়, যা লাইটওয়েট থ্রেড হিসেবে কাজ করে এবং সিস্টেমের রিসোর্স কম খরচ করে।
- Channels: Goroutines এর মধ্যে ডেটা আদান-প্রদান করতে channels ব্যবহার করা হয়। এটি সিঙ্ক্রোনাইজড ডেটা ট্রান্সফার নিশ্চিত করে।
- WaitGroup: একাধিক goroutines এর সমন্বয় এবং সিঙ্ক্রোনাইজেশন নিশ্চিত করার জন্য
sync.WaitGroupব্যবহার করা হয়। - Select Statement: একাধিক চ্যানেল থেকে ডেটা গ্রহণ করতে
selectস্টেটমেন্ট ব্যবহৃত হয়।
Go তে কনকারেন্সি খুবই সহজ এবং কার্যকরী, এবং এটি দ্রুত এবং দক্ষ প্রোগ্রাম তৈরি করতে সাহায্য করে, বিশেষত ওয়েব সার্ভিস এবং বড় স্কেল অ্যাপ্লিকেশন তৈরি করার ক্ষেত্রে।
Go-তে Concurrency মডেল এবং Goroutines
১. Go এর Concurrency মডেল
Go-এর concurrency মডেল হল এর একটি শক্তিশালী এবং মৌলিক বৈশিষ্ট্য যা বিভিন্ন কাজ বা থ্রেড একসাথে চালানোর প্রক্রিয়াকে সহজ করে তোলে। Concurrency হল এমন একটি কার্যক্রম যেখানে একাধিক কাজ একসঙ্গে চলতে পারে, তবে একে সম্পূর্ণভাবে একসময় একই CPU কোরে চালানো হয় না। Go তে concurrency এর মডেল খুবই সহজ এবং সিম্পল।
Go-তে Concurrency মডেল সাধারণত Goroutines এবং Channels এর মাধ্যমে কাজ করে। এটি Lightweight এবং Highly Efficient।
Go তে concurrency চালানো মূলত Goroutines ব্যবহার করে, যা সিস্টেম থ্রেডের তুলনায় অনেক বেশি হালকা এবং মেমরি ব্যবহারকারী। Go নিজে থেকেই একাধিক Goroutines পরিচালনা করে থাকে, যার ফলে একাধিক কাজ সহজভাবে একসঙ্গে চালানো যায়।
২. Goroutines (গোরাউটিনস)
Goroutines হল Go তে concurrency পরিচালনার একটি মেকানিজম। একটি Goroutine হল একটি থ্রেড যা আলাদাভাবে কাজ করতে সক্ষম, তবে এটি সিস্টেম থ্রেডের তুলনায় অনেক হালকা এবং দ্রুত কার্যকরী।
Goroutine শুরু করতে go কিওয়ার্ড ব্যবহার করা হয়, যা একটি ফাংশন বা কোড ব্লককে এক স্বাধীন থ্রেডে চালানোর জন্য নির্দেশ দেয়।
২.১ Goroutine তৈরি করার সাধারণ সিনট্যাক্স
go functionName()এখানে functionName() একটি ফাংশন কল হবে, তবে এটি একটি Goroutine হিসেবে চলবে।
২.২ Goroutine উদাহরণ
package main
import "fmt"
import "time"
// Goroutine কাজ করতে হবে এমন একটি ফাংশন
func printNumbers() {
for i := 1; i <= 5; i++ {
fmt.Println(i)
time.Sleep(100 * time.Millisecond) // Sleep এর মাধ্যমে বিলম্ব করা
}
}
func main() {
// Goroutine তৈরি করা
go printNumbers()
// Main ফাংশনেও কিছু কাজ চলছে
fmt.Println("Main function is running")
// এক্ষেত্রে Goroutine শেষ না হওয়া পর্যন্ত main function শেষ হতে পারে না
time.Sleep(600 * time.Millisecond) // main ফাংশন অপেক্ষা করবে
}এখানে, printNumbers() ফাংশনটি একটি Goroutine হিসেবে চালানো হয়েছে, যা প্যারালালভাবে কাজ করছে। কিন্তু যেহেতু main ফাংশনটি তাড়াতাড়ি শেষ হয়ে যেতে পারে, তাই আমরা time.Sleep() দিয়ে কিছু সময় অপেক্ষা করছি, যাতে Goroutineটি সম্পূর্ণ হতে পারে।
আউটপুট:
Main function is running
1
2
3
4
5এখানে, printNumbers() ফাংশনটি Goroutine হিসেবে চলতে শুরু করে এবং তার আউটপুট main ফাংশনের আউটপুটের পরে আসছে।
২.৩ Goroutines এর সুবিধা
- Lightweight: Goroutines সিস্টেম থ্রেডের তুলনায় অনেক কম মেমরি ব্যবহার করে এবং দ্রুত সৃষ্ট হয়।
- Parallel Execution: একটি কোড একাধিক Goroutine এ ভাগ করে কার্যকরভাবে একই সময়ে একাধিক কাজ করা যায়।
- Efficient Scheduling: Go runtime নিজেই Goroutines গুলোর সিডিউলিং এবং ম্যানেজমেন্ট করে, যা সিস্টেমের পারফরম্যান্সকে আরও উন্নত করে।
৩. Channels (চ্যানেলস)
Channels হল Go তে বিভিন্ন Goroutines এর মধ্যে ডেটা আদান-প্রদান করার উপায়। এটি একটি টাইপ সেফ মেকানিজম, যা এক Goroutine থেকে আরেকটি Goroutine এ ডেটা পাঠাতে ব্যবহৃত হয়। Go তে channels ব্যবহার করে আপনি নিরাপদভাবে একাধিক Goroutine এর মধ্যে যোগাযোগ স্থাপন করতে পারেন।
৩.১ Channel ডিক্লারেশন এবং ব্যবহার
Channels ডিক্লেয়ার করতে chan কিওয়ার্ড ব্যবহার করা হয়:
var ch chan int // channel ডিক্লেয়ার করাএবং ডেটা পাঠাতে ch <- value এবং ডেটা গ্রহণ করতে value := <- ch ব্যবহার করা হয়।
৩.২ Channel উদাহরণ
package main
import "fmt"
func printNumbers(ch chan int) {
for i := 1; i <= 5; i++ {
ch <- i // channel এ মান পাঠানো
}
close(ch) // channel বন্ধ করা
}
func main() {
ch := make(chan int) // channel তৈরি করা
// Goroutine হিসেবে printNumbers ফাংশন কল করা
go printNumbers(ch)
// channel থেকে মান পড়া
for num := range ch {
fmt.Println(num) // আউটপুট: 1, 2, 3, 4, 5
}
}এখানে, printNumbers ফাংশনটি একটি Goroutine হিসেবে চালানো হয়েছে এবং channel ch এর মাধ্যমে main ফাংশনে ডেটা পাঠানো হয়েছে। main ফাংশনে চ্যানেল থেকে ডেটা গ্রহণ করা হয়েছে এবং তা প্রিন্ট করা হয়েছে।
৩.৩ Buffered Channels (বাফার্ড চ্যানেলস)
একটি buffered channel এমন একটি চ্যানেল যেখানে আপনি নির্দিষ্ট সংখ্যা পর্যন্ত ডেটা পাঠাতে পারেন, এরপরে তা গ্রহণ না হওয়া পর্যন্ত চ্যানেল পূর্ণ হয়ে যাবে। এটি asynchronous কমিউনিকেশনের জন্য ব্যবহার করা যায়।
package main
import "fmt"
func main() {
ch := make(chan int, 3) // একটি buffered channel
ch <- 1 // channel এ মান পাঠানো
ch <- 2
ch <- 3
fmt.Println(<-ch) // আউটপুট: 1
fmt.Println(<-ch) // আউটপুট: 2
fmt.Println(<-ch) // আউটপুট: 3
}এখানে, buffered channel এর আকার 3, তাই আমরা চ্যানেলে তিনটি মান পাঠাতে পারি এবং এরপর তা গ্রহণ করতে পারি।
৪. Select Statement
Select কিওয়ার্ড ব্যবহার করে Go-তে একাধিক channels থেকে একাধিক কাজের জন্য blocking অপারেশন করতে সাহায্য করে। এটি অনেকগুলো Goroutine এবং Channel এর মধ্যে সঠিক সিঙ্ক্রোনাইজেশন নিশ্চিত করতে ব্যবহৃত হয়।
৪.১ Select উদাহরণ
package main
import "fmt"
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() { ch1 <- "Hello from channel 1" }()
go func() { ch2 <- "Hello from channel 2" }()
// Select দিয়ে একাধিক চ্যানেল থেকে ডেটা গ্রহণ করা
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
}এখানে, select একটি channel থেকে ডেটা গ্রহণ করবে এবং যেই channel প্রথমে মান পাঠাবে, সেটির মান প্রিন্ট হবে।
সারসংক্ষেপ
- Concurrency: Go তে concurrency ব্যবস্থাপনার জন্য Goroutines এবং Channels ব্যবহৃত হয়, যা সহজেই একাধিক কাজ একসাথে চালাতে সহায়তা করে।
- Goroutines: Goroutines হল Go তে concurrency পরিচালনার একটি হালকা থ্রেড যা কোডের বিভিন্ন অংশকে একযোগে চালাতে সক্ষম।
- Channels: Channels একটি শক্তিশালী মেকানিজম যা Goroutines এর মধ্যে ডেটা আদান-প্রদান করতে ব্যবহৃত হয়।
- Buffered Channels: Buffered channels ডেটা ধারন করতে সক্ষম এবং এগুলি asynchronous কমিউনিকেশনের জন্য ব্যবহৃত হয়।
- Select: Select কিওয়ার্ড একাধিক channels থেকে ডেটা অ্যাক্সেস করতে ব্যবহৃত হয়, যা concurrency এর সাথে কাজ করার জন্য উপযোগী।
Go তে Concurrency মডেল এবং Goroutines এর মাধ্যমে আপনি দক্ষভাবে বহু-কার্য (multi-tasking) বা উচ্চ-পারফরম্যান্স অ্যাপ্লিকেশন তৈরি করতে পারবেন।
Go-তে Goroutines তৈরি এবং পরিচালনা
Goroutines হল Go ভাষার একটি গুরুত্বপূর্ণ বৈশিষ্ট্য যা concurrency (একই সময়ে একাধিক কাজ করার ক্ষমতা) প্রদান করে। গোরাউটিন হল Go ভাষার একটি থ্রেড-হালকা সমান্তরাল একক কার্যক্রম (lightweight concurrent unit of execution), যা ডেভেলপারদের সহজে কনকারেন্ট প্রোগ্রামিং করতে সহায়তা করে। এটি আপনাকে একাধিক কাজ একসঙ্গে চালানোর সুযোগ দেয় এবং সিস্টেমের প্রোসেসিং ক্ষমতাকে পুরোপুরি ব্যবহার করতে সাহায্য করে।
Go তে goroutine খুবই হালকা এবং দ্রুত কার্যকরী, যেহেতু সেগুলি স্বয়ংক্রিয়ভাবে সিস্টেমের থ্রেডগুলোর সাথে ম্যানেজ করা হয়। এটি ব্যবহারে খুব কম মেমরি ব্যবহার হয় এবং একাধিক গোরাউটিন সহজেই একসাথে রান করা সম্ভব।
১. Goroutines কি?
Goroutines হল lightweight threads যা সিপিইউ-এ থ্রেড স্পেস শেয়ার করে। এগুলি খুব দ্রুত এবং সহজভাবে চালানো যায়। Go তে গোরাউটিন তৈরি করতে, go কিওয়ার্ড ব্যবহার করা হয়।
১.১ Goroutine তৈরি করা
Go-তে একটি গোরাউটিন তৈরি করার জন্য go কিওয়ার্ড ব্যবহার করা হয়:
package main
import "fmt"
func printMessage() {
fmt.Println("Hello from Goroutine!")
}
func main() {
// Goroutine তৈরি করা
go printMessage()
// main ফাংশনে আরও কিছু কাজ করা
fmt.Println("Hello from main function!")
// কিছু সময় অপেক্ষা করা
fmt.Scanln() // ইন্টারেকটিভ ইনপুটের জন্য, যাতে গোরাউটিন সম্পন্ন হওয়ার আগে প্রোগ্রাম শেষ না হয়
}এখানে, go printMessage() লাইনের মাধ্যমে printMessage() ফাংশনটি একটি গোরাউটিন হিসেবে চালানো হয়েছে। এর ফলে এটি main ফাংশনের সাথে সমান্তরালে (concurrently) কাজ করবে। fmt.Scanln() ব্যবহার করা হয়েছে যাতে গোরাউটিনটি সম্পন্ন হওয়ার আগে প্রোগ্রাম শেষ না হয়।
আউটপুট:
Hello from main function!
Hello from Goroutine!এখানে, গোরাউটিনটি printMessage ফাংশনটি একটি আলাদা থ্রেডে চালিয়েছে, এবং main ফাংশনটি তার কাজ সম্পন্ন হয়েছে।
২. Multiple Goroutines তৈরি করা
একাধিক গোরাউটিন তৈরি এবং পরিচালনা করা খুবই সহজ। আপনি একইভাবে অনেক গোরাউটিন তৈরি করে, একাধিক কাজ সমান্তরালে চালাতে পারেন।
২.১ Multiple Goroutines Example
package main
import "fmt"
func printMessage(msg string) {
fmt.Println(msg)
}
func main() {
// একাধিক Goroutine তৈরি করা
go printMessage("Hello from Goroutine 1")
go printMessage("Hello from Goroutine 2")
go printMessage("Hello from Goroutine 3")
// main ফাংশন কিছুক্ষণ অপেক্ষা করবে
fmt.Scanln() // এখানে ব্যবহারকারী ইনপুট না দিলে গোরাউটিনগুলো শেষ হবেনা
}এখানে, তিনটি গোরাউটিন তৈরি করা হয়েছে যা আলাদা আলাদা বার্তা প্রিন্ট করবে। এই গোরাউটিনগুলো একসঙ্গে চলবে।
আউটপুট:
Hello from Goroutine 1
Hello from Goroutine 2
Hello from Goroutine 3এখানে, যেহেতু গোরাউটিনগুলো একসাথে চলে, আউটপুটের অনুক্রম পরিবর্তিত হতে পারে।
৩. Goroutines এর Synchronization (সিঙ্ক্রোনাইজেশন)
যেহেতু গোরাউটিনগুলো সমান্তরালে চলতে থাকে, মাঝে মাঝে আপনি নিশ্চিত করতে চান যে একটি গোরাউটিন কিছু কাজ শেষ হওয়ার পর অন্য গোরাউটিন কাজ শুরু করবে। এই প্রক্রিয়া সিঙ্ক্রোনাইজেশন হিসেবে পরিচিত। Go-তে সিঙ্ক্রোনাইজেশনের জন্য বিভিন্ন টুল রয়েছে, যেমন WaitGroups, Channels।
৩.১ WaitGroup ব্যবহার করা
sync.WaitGroup ব্যবহার করে আপনি গোরাউটিনগুলির কার্যক্রমের শেষ পর্যন্ত অপেক্ষা করতে পারেন।
package main
import (
"fmt"
"sync"
)
func printMessage(msg string, wg *sync.WaitGroup) {
defer wg.Done() // গোরাউটিন সম্পন্ন হলে ওয়েটগ্রুপ থেকে এক ইউনিট কমানো হবে
fmt.Println(msg)
}
func main() {
var wg sync.WaitGroup
// WaitGroup এ 3টি গোরাউটিন যোগ করা
wg.Add(3)
go printMessage("Hello from Goroutine 1", &wg)
go printMessage("Hello from Goroutine 2", &wg)
go printMessage("Hello from Goroutine 3", &wg)
// গোরাউটিনগুলির কাজ শেষ হওয়া পর্যন্ত অপেক্ষা করা
wg.Wait()
fmt.Println("All Goroutines completed!")
}এখানে, wg.Add(3) দ্বারা তিনটি গোরাউটিনের জন্য অপেক্ষা করা হবে এবং wg.Done() প্রতিটি গোরাউটিন শেষে কল হবে। wg.Wait() ফাংশনটি গোরাউটিনগুলো সম্পন্ন না হওয়া পর্যন্ত main ফাংশন থেমে থাকবে।
আউটপুট:
Hello from Goroutine 1
Hello from Goroutine 2
Hello from Goroutine 3
All Goroutines completed!এখানে, গোরাউটিনগুলো যখন সব শেষ হবে, তখন main ফাংশনটি তার পরবর্তী কাজ সম্পন্ন করবে।
৪. Channels এর মাধ্যমে Goroutines পরিচালনা
Channels ব্যবহার করে আপনি গোরাউটিনগুলির মধ্যে ডেটা আদান-প্রদান করতে পারেন এবং তাদের সমন্বয় করতে পারেন। Channel গুলি গোরাউটিনগুলির মধ্যে তথ্য শেয়ার করার জন্য ব্যবহৃত হয়।
৪.১ Channel ব্যবহার করে Goroutines পরিচালনা
package main
import "fmt"
func printMessage(msg string, ch chan string) {
ch <- msg // Channel এর মাধ্যমে বার্তা পাঠানো
}
func main() {
ch := make(chan string) // Channel তৈরি করা
// গোরাউটিন তৈরি করা
go printMessage("Hello from Goroutine", ch)
// Channel থেকে ডেটা গ্রহণ করা
message := <-ch
fmt.Println(message)
}এখানে, printMessage ফাংশনটি একটি string টাইপের Channel ব্যবহার করে তার বার্তা পাঠাচ্ছে। main ফাংশনটি Channel থেকে বার্তা গ্রহণ করে তা প্রিন্ট করছে।
আউটপুট:
Hello from Goroutine৪.২ Multiple Goroutines with Channels
package main
import "fmt"
func sendData(ch chan string) {
ch <- "Data sent!"
}
func main() {
ch := make(chan string)
// Multiple Goroutines
go sendData(ch)
go sendData(ch)
// Receive data from the channel
msg1 := <-ch
msg2 := <-ch
fmt.Println(msg1) // আউটপুট: Data sent!
fmt.Println(msg2) // আউটপুট: Data sent!
}এখানে, দুটি গোরাউটিন Channel মাধ্যমে ডেটা পাঠাচ্ছে এবং main ফাংশনটি Channel থেকে সেই ডেটা গ্রহণ করছে।
সারসংক্ষেপ
- Goroutines: Go তে গোরাউটিন হলো হালকা থ্রেড যা concurrency সুবিধা প্রদান করে। এটি
goকিওয়ার্ড ব্যবহার করে তৈরি করা হয়। - Synchronization: WaitGroup ব্যবহার করে গোরাউটিনগুলির কার্যক্রম সিঙ্ক্রোনাইজ করা যায়।
- Channels: গোরাউটিনগুলির মধ্যে ডেটা আদান-প্রদান এবং তাদের সমন্বয় করার জন্য Channels ব্যবহৃত হয়।
Go তে Goroutines এবং Channels এর মাধ্যমে আপনি সহজে কনকারেন্ট প্রোগ্রামিং করতে পারবেন, যা আপনার অ্যাপ্লিকেশনকে আরও কার্যকর এবং স্কেলেবল করে তুলবে।
Go-তে Channels এর মাধ্যমে Inter-Goroutine Communication
Go-তে channels একটি শক্তিশালী ফিচার যা goroutines এর মধ্যে ডেটা আদান-প্রদান করতে ব্যবহৃত হয়। Goroutines হল একটি হালকা থ্রেড যা Go-তে কনকারেন্সি (concurrency) সাপোর্ট করার জন্য ব্যবহৃত হয়। যখন আপনি একাধিক goroutines চালান এবং তাদের মধ্যে ডেটা শেয়ার করতে চান, তখন channels ব্যবহার করা হয়।
Channels গুলি একই টাইপের ডেটা ধারণ করতে পারে এবং এক goroutine অন্য goroutine-এ ডেটা পাঠাতে বা গ্রহণ করতে ব্যবহার করে। সুতরাং, goroutines এর মধ্যে নিরাপদ এবং দক্ষভাবে ডেটা আদান-প্রদান সম্ভব হয়।
১. Channel তৈরি করা
Channels তৈরি করতে make ফাংশন ব্যবহার করা হয়। একটি channel তৈরি করার সময় আপনি টাইপ নির্ধারণ করতে পারেন, যা channel সেই টাইপের ডেটা ধারণ করবে।
channel := make(chan int)এখানে, channel একটি channel যা int টাইপের ডেটা ধারণ করবে।
২. Channel-এ ডেটা পাঠানো (Send)
Go-তে channel-এ ডেটা পাঠাতে <- অপারেটর ব্যবহার করা হয়। একটি goroutine অন্য goroutine-এ ডেটা পাঠাতে channel <- value ব্যবহার করে।
package main
import "fmt"
func main() {
channel := make(chan int) // channel তৈরি করা
// goroutine চালানো
go func() {
channel <- 42 // channel এ ডেটা পাঠানো
}()
value := <-channel // channel থেকে ডেটা গ্রহণ করা
fmt.Println(value) // আউটপুট: 42
}এখানে, একটি goroutine channel-এ একটি মান পাঠিয়েছে এবং মূল goroutine তা গ্রহণ করেছে।
৩. Channel থেকে ডেটা গ্রহণ (Receive)
ডেটা গ্রহণ করতে, আপনি <-channel ব্যবহার করবেন। এটি channel থেকে মান গ্রহণ করবে এবং সেই মানের সাথে কাজ করবে।
package main
import "fmt"
func main() {
channel := make(chan int)
// goroutine চালানো
go func() {
channel <- 100 // channel এ ডেটা পাঠানো
}()
value := <-channel // channel থেকে ডেটা গ্রহণ করা
fmt.Println(value) // আউটপুট: 100
}এখানে, main ফাংশন channel থেকে ডেটা গ্রহণ করছে এবং তা প্রিন্ট করছে।
৪. Buffered Channels (বাফারড চ্যানেল)
Go তে Buffered Channels ব্যবহার করা যায়, যেখানে একটি নির্দিষ্ট সাইজের channel তৈরি করা হয়, যাতে কিছু ডেটা পূর্বেই সংরক্ষণ করা যেতে পারে। এর মাধ্যমে আপনি একাধিক ডেটা প্রেরণ করতে পারেন, যা পরবর্তীতে অন্য goroutine দ্বারা গ্রহণ করা হবে।
make(chan int, 3) ব্যবহার করে একটি বাফারড চ্যানেল তৈরি করা হয়, যেখানে ৩টি মান একসাথে প্রেরণ করা যেতে পারে।
package main
import "fmt"
func main() {
// একটি বাফারড channel তৈরি করা
channel := make(chan int, 3)
// goroutine চালানো
go func() {
channel <- 10 // 1st value
channel <- 20 // 2nd value
channel <- 30 // 3rd value
}()
// channel থেকে ডেটা গ্রহণ
fmt.Println(<-channel) // আউটপুট: 10
fmt.Println(<-channel) // আউটপুট: 20
fmt.Println(<-channel) // আউটপুট: 30
}এখানে, channel ৩টি মান ধারণ করতে সক্ষম, এবং একে একে সেগুলো গ্রহণ করা হয়েছে।
৫. Select Statement (চয়ন স্টেটমেন্ট)
Select স্টেটমেন্ট ব্যবহার করে আপনি একাধিক channel-এ ডেটা পাঠাতে বা গ্রহণ করতে পারেন। এটি switch statement এর মতো কাজ করে, তবে এটি শুধুমাত্র channels এর সাথে কাজ করে। একটি select ব্লক একাধিক channel অপারেশনকে ম্যানেজ করে এবং প্রথমে যেটি প্রস্তুত হয়, সেটি নির্বাচন করা হয়।
৫.১ Select Statement উদাহরণ
package main
import "fmt"
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
ch1 <- "Hello from ch1"
}()
go func() {
ch2 <- "Hello from ch2"
}()
// Select statement দিয়ে channel থেকে ডেটা গ্রহণ
select {
case msg1 := <-ch1:
fmt.Println(msg1) // আউটপুট: Hello from ch1
case msg2 := <-ch2:
fmt.Println(msg2) // আউটপুট: Hello from ch2
}
}এখানে, দুটি goroutine চালানো হয়েছে যা দুটি channel-এ ডেটা পাঠাচ্ছে। select স্টেটমেন্ট একবারে একটি channel থেকে ডেটা গ্রহণ করবে, তবে যেকোনো একটি channel প্রথমে প্রস্তুত হবে সেটি নির্বাচন করা হবে।
৬. Channel বন্ধ করা (Close)
Go তে channel বন্ধ করতে close() ফাংশন ব্যবহার করা হয়। যখন একটি channel বন্ধ হয়ে যায়, তখন আর ডেটা পাঠানো সম্ভব হয় না, তবে ডেটা গ্রহণ করা সম্ভব হয়।
৬.১ Channel Close উদাহরণ
package main
import "fmt"
func main() {
channel := make(chan int)
// goroutine চালানো
go func() {
channel <- 42
close(channel) // channel বন্ধ করা
}()
value := <-channel // channel থেকে ডেটা গ্রহণ করা
fmt.Println(value) // আউটপুট: 42
_, ok := <-channel // channel থেকে আরও ডেটা গ্রহণের চেষ্টা
fmt.Println(ok) // আউটপুট: false (যেহেতু channel বন্ধ)
}এখানে, close(channel) ফাংশন দিয়ে channel বন্ধ করা হয়েছে। পরে, channel থেকে আর কোনো ডেটা গ্রহণ করা সম্ভব নয়, এবং ok ভেরিয়েবল false হয়ে যাবে।
৭. Channels এর সুবিধা
- Goroutines এর মধ্যে ডেটা শেয়ার করা: Channels এর মাধ্যমে আপনি একাধিক goroutines-এর মধ্যে ডেটা শেয়ার করতে পারেন।
- Synchronization: Channels প্রক্রিয়াগুলির মধ্যে synchronization নিশ্চিত করে।
- Deadlock এড়ানো: Channels ব্যবহারের মাধ্যমে goroutines-এর মধ্যে নিরাপদভাবে ডেটা আদান-প্রদান করা যায়, যা ডেডলক (deadlock) এড়াতে সহায়তা করে।
সারসংক্ষেপ
- Channels: এটি Go তে goroutines-এর মধ্যে ডেটা শেয়ার করার জন্য ব্যবহৃত একটি গুরুত্বপূর্ণ টুল।
- Buffered Channels: এগুলি একটি নির্দিষ্ট সাইজের channel, যেখানে ডেটা একে একে স্টোর করা যায়।
- Select: একাধিক channel-এর মধ্যে ডেটা আদান-প্রদান করার জন্য
selectব্যবহার করা হয়। - Close: Channel বন্ধ করতে
close()ফাংশন ব্যবহার করা হয়, যা channel থেকে ডেটা গ্রহণ করতে সহায়ক হয়।
Go তে channels ব্যবহারের মাধ্যমে goroutines এর মধ্যে কার্যকরী ডেটা আদান-প্রদান এবং synchronization করা সম্ভব, যা কনকারেন্সি প্রোগ্রামিংয়ের জন্য খুবই উপকারী।
Go তে select স্টেটমেন্ট এবং Concurrent Programming
Go প্রোগ্রামিং ভাষা একটি শক্তিশালী কনকারেন্সি মডেল সমর্থন করে, যা আপনাকে একাধিক কাজ একসাথে (concurrently) চালানোর সুবিধা দেয়। এর জন্য Go-তে goroutines এবং channels ব্যবহৃত হয়। select স্টেটমেন্ট Go তে কনকারেন্সি পরিচালনার একটি অত্যন্ত গুরুত্বপূর্ণ উপাদান, যা একাধিক channel এর মধ্যে একযোগভাবে কাজ করতে সাহায্য করে।
১. select স্টেটমেন্ট
Go তে select একটি কনকারেন্ট প্রোগ্রামিং কনস্ট্রাক্ট যা একাধিক চ্যানেলের মধ্যে ইভেন্ট (মেসেজ) পাঠানোর বা গ্রহণ করার কাজ করে। এটি ঠিক যেমন switch স্টেটমেন্ট কাজ করে, তেমনই একাধিক চ্যানেলের মধ্যে নির্বাচন করে প্রথমে যে চ্যানেলটি প্রস্তুত হয়, তার সাথে কাজ শুরু করে।
১.১ select স্টেটমেন্টের সিনট্যাক্স
select {
case channel1 <- value:
// channel1 থেকে ডেটা পাঠানোর সময় যা করতে হবে
case value := <-channel2:
// channel2 থেকে ডেটা গ্রহণ করার সময় যা করতে হবে
case value, ok := <-channel3:
// channel3 থেকে ডেটা গ্রহণ এবং চেক করার সময় যা করতে হবে
default:
// যদি কোনো চ্যানেল প্রস্তুত না হয়, তবে যা করতে হবে
}- case: এটি প্রতিটি চ্যানেলের জন্য একটি বিকল্প।
- <-channel: চ্যানেল থেকে ডেটা পাঠানো বা গ্রহণ করা।
- default: যদি কোন চ্যানেল প্রস্তুত না থাকে, তবে এটি একটি বিকল্প প্রদান করে।
১.২ select উদাহরণ
package main
import "fmt"
import "time"
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(2 * time.Second)
ch1 <- "Data from channel 1"
}()
go func() {
time.Sleep(1 * time.Second)
ch2 <- "Data from channel 2"
}()
// select statement
select {
case msg1 := <-ch1:
fmt.Println("Received:", msg1)
case msg2 := <-ch2:
fmt.Println("Received:", msg2)
}
}এখানে, দুটি goroutine দুটি আলাদা চ্যানেলে মেসেজ পাঠাচ্ছে। select স্টেটমেন্টটি প্রথমে যে চ্যানেল থেকে মেসেজ প্রাপ্ত হবে, তা গ্রহণ করবে এবং প্রিন্ট করবে। যেহেতু ch2 থেকে মেসেজ ১ সেকেন্ড পরে আসবে এবং ch1 থেকে ২ সেকেন্ড পরে আসবে, ch2 থেকে মেসেজ আগে আসবে এবং এটি প্রিন্ট হবে।
আউটপুট:
Received: Data from channel 2১.৩ default case
যদি কোনও চ্যানেল প্রস্তুত না থাকে, তাহলে default ব্লকটি চালানো হয়। এটি এমন অবস্থায় কাজে লাগে যখন আপনি অন্য কাজ করতে চান যদি কোনও চ্যানেল প্রস্তুত না হয়।
package main
import "fmt"
func main() {
ch := make(chan string)
select {
case msg := <-ch:
fmt.Println("Received:", msg)
default:
fmt.Println("No message received, default case executed")
}
}এখানে, ch চ্যানেলটি বন্ধ বা কিছু পাঠানো হয়নি, তাই default ব্লকটি কার্যকর হবে।
আউটপুট:
No message received, default case executed২. Concurrent Programming in Go (কনকারেন্ট প্রোগ্রামিং)
Go তে কনকারেন্ট প্রোগ্রামিং খুবই সহজ এবং শক্তিশালী। Go-তে কনকারেন্ট প্রোগ্রামিং এর মূল দুটি উপাদান হল goroutines এবং channels।
২.১ Goroutines
Goroutines হল একটি প্রোগ্রাম চালানোর ছোট থ্রেড। Go তে, আপনি সহজে কনকারেন্ট ফাংশন চালাতে পারেন go কিওয়ার্ড ব্যবহার করে।
package main
import "fmt"
func printMessage(message string) {
fmt.Println(message)
}
func main() {
go printMessage("Hello from Goroutine 1")
go printMessage("Hello from Goroutine 2")
fmt.Println("Main function")
}এখানে, go কিওয়ার্ড দ্বারা printMessage ফাংশন দুটি আলাদা goroutines হিসেবে চালানো হবে, এবং এগুলি একই সময় চালু থাকবে। তবে, main ফাংশনটি প্রথমে সম্পন্ন হতে পারে, কারণ goroutines এর কার্যকলাপ কখনও শেষ হবে বা কমপ্লিট হবে এমন নির্দিষ্ট সময় নেই।
আউটপুট:
Main function
Hello from Goroutine 1
Hello from Goroutine 2২.২ Channels
Channels হল এমন একটি মেকানিজম যা goroutines-এর মধ্যে ডেটা আদান-প্রদান করতে ব্যবহৃত হয়। আপনি একটি goroutine থেকে অন্য একটি goroutine এ ডেটা পাঠাতে channels ব্যবহার করতে পারেন।
package main
import "fmt"
func sendData(ch chan string) {
ch <- "Hello from Goroutine"
}
func main() {
ch := make(chan string) // channel তৈরি করা
go sendData(ch) // goroutine চালানো
// channel থেকে ডেটা গ্রহণ করা
message := <-ch
fmt.Println(message)
}এখানে, একটি goroutine sendData ফাংশন থেকে একটি মেসেজ পাঠাচ্ছে ch চ্যানেলে এবং main ফাংশনটি তা গ্রহণ করে প্রিন্ট করছে।
আউটপুট:
Hello from Goroutine২.৩ Goroutines এবং Channels এর মাধ্যমে কনকারেন্সি
package main
import "fmt"
func printNumbers(ch chan int) {
for i := 1; i <= 5; i++ {
ch <- i
}
close(ch) // চ্যানেল বন্ধ করা
}
func main() {
ch := make(chan int)
go printNumbers(ch) // goroutine চালানো
for num := range ch {
fmt.Println(num) // চ্যানেল থেকে ডেটা গ্রহণ করা
}
}এখানে, printNumbers ফাংশনটি একটি chan ব্যবহার করে ১ থেকে ৫ পর্যন্ত সংখ্যা পাঠাচ্ছে, এবং main ফাংশন সেই সংখ্যা গ্রহণ করছে এবং প্রিন্ট করছে।
আউটপুট:
1
2
3
4
5৩. Select with Multiple Channels (একাধিক চ্যানেলের সাথে Select)
select স্টেটমেন্ট একাধিক চ্যানেলের মধ্যে যেকোনো একটিকে সিলেক্ট করতে ব্যবহৃত হয়। এটি আপনাকে একাধিক চ্যানেল থেকে ডেটা গ্রহণ করতে বা পাঠাতে একসাথে কাজ করার সুবিধা দেয়।
package main
import "fmt"
import "time"
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(2 * time.Second)
ch1 <- "Message from channel 1"
}()
go func() {
time.Sleep(1 * time.Second)
ch2 <- "Message from channel 2"
}()
// select statement
select {
case msg1 := <-ch1:
fmt.Println("Received:", msg1)
case msg2 := <-ch2:
fmt.Println("Received:", msg2)
}
}এখানে, ch1 এবং ch2 দুটি চ্যানেল থেকে মেসেজ পাঠানো হচ্ছে, এবং select স্টেটমেন্ট প্রথমে যেই চ্যানেল থেকে মেসেজ পাবে সেটি সিলেক্ট করবে।
আউটপুট:
Received: Message from channel 2সারসংক্ষেপ
- select স্টেটমেন্ট: একাধিক চ্যানেলের মধ্যে যেকোনো একটিকে নির্বাচন করে কাজ করতে ব্যবহৃত হয়। এটি কনকারেন্ট প্রোগ্রামিংয়ে চ্যানেল ব্যবহারের একটি শক্তিশালী উপাদান।
- Goroutines: Go তে ছোট থ্রেড চালানোর জন্য
goকিওয়ার্ড ব্যবহৃত হয়, যা কনকারেন্ট কাজ করতে সহায়তা করে। - Channels: Goroutines-এর মধ্যে ডেটা আদান-প্রদান করার জন্য channels ব্যবহৃত হয়, যা একাধিক goroutines এর মধ্যে সিঙ্ক্রোনাইজেশন এবং ডেটা শেয়ারিং সহজ করে তোলে।
Go তে Concurrent Programming এবং select স্টেটমেন্ট ব্যবহার করে আপনি অনেক বেশি নমনীয় এবং দক্ষ প্রোগ্রামিং করতে পারেন।
Read more