In Go, WaitGroups and Mutex are two important synchronization mechanisms used to coordinate the execution of concurrent goroutines. They help in managing the flow of goroutines, ensuring that tasks are completed or data access is controlled appropriately.
A WaitGroup is used to wait for a collection of goroutines to finish executing. It allows one or more goroutines to wait for others to complete before continuing with the program.
Add(n int)
: Increments the counter by n
. Typically, you would call this before starting any goroutines to indicate how many goroutines to wait for.Done()
: Decrements the counter by 1. Each goroutine should call this once it finishes its work.Wait()
: Blocks until the counter is zero, meaning all goroutines have completed.package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
// Adding 2 goroutines to the WaitGroup
wg.Add(2)
// First goroutine
go func() {
defer wg.Done() // Decrement the counter when done
time.Sleep(2 * time.Second)
fmt.Println("Goroutine 1 finished")
}()
// Second goroutine
go func() {
defer wg.Done() // Decrement the counter when done
time.Sleep(1 * time.Second)
fmt.Println("Goroutine 2 finished")
}()
// Wait for all goroutines to finish
wg.Wait()
fmt.Println("All goroutines finished")
}
🔹 Output:
Goroutine 2 finished
Goroutine 1 finished
All goroutines finished
👉 In this example, wg.Wait()
ensures that the program waits for both goroutines to finish before printing "All goroutines finished."
A Mutex is used to ensure that only one goroutine can access a particular section of code at a time, preventing data races. It provides mutual exclusion when accessing shared resources.
Lock()
: Acquires the lock. If another goroutine already holds the lock, the calling goroutine will block until the lock is available.Unlock()
: Releases the lock. This allows other goroutines to acquire the lock and continue their work.package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
)
func increment() {
mu.Lock() // Lock the mutex before accessing the shared resource
counter++
mu.Unlock() // Unlock the mutex after updating the counter
}
func main() {
var wg sync.WaitGroup
// Add 5 goroutines to the WaitGroup
wg.Add(5)
// Start 5 goroutines that increment the counter
for i := 0; i < 5; i++ {
go func() {
defer wg.Done() // Decrement the counter when done
increment()
}()
}
// Wait for all goroutines to finish
wg.Wait()
fmt.Println("Counter value:", counter)
}
🔹 Output:
Counter value: 5
👉 In this example, a Mutex is used to prevent multiple goroutines from simultaneously accessing and modifying the counter
variable, ensuring the result is accurate.
You can combine WaitGroups and Mutex to coordinate goroutines while also ensuring that shared resources are accessed safely.
package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
)
func increment(wg *sync.WaitGroup) {
mu.Lock()
counter++
mu.Unlock()
wg.Done()
}
func main() {
var wg sync.WaitGroup
// Add 5 goroutines to the WaitGroup
wg.Add(5)
// Start 5 goroutines that increment the counter
for i := 0; i < 5; i++ {
go increment(&wg)
}
// Wait for all goroutines to finish
wg.Wait()
fmt.Println("Final Counter value:", counter)
}
🔹 Output:
Final Counter value: 5
👉 In this case, the WaitGroup ensures that the main function waits for all goroutines to finish, and the Mutex ensures that the counter is safely incremented by one goroutine at a time.
Go-তে WaitGroups এবং Mutex দুটি গুরুত্বপূর্ণ সিঙ্ক্রোনাইজেশন মেকানিজম যা concurent goroutines-এর এক্সিকিউশন নিয়ন্ত্রণ করতে ব্যবহৃত হয়। এগুলি goroutines-এর প্রবাহ পরিচালনা করতে এবং ডেটা অ্যাক্সেস নিয়ন্ত্রণ করতে সাহায্য করে।
একটি WaitGroup ব্যবহার করা হয় একাধিক goroutines-এর কাজ শেষ হওয়া পর্যন্ত অপেক্ষা করতে। এটি একটি বা একাধিক goroutine-এর কাজ শেষ হওয়া পর্যন্ত প্রোগ্রাম চলমান রাখে।
Add(n int)
: কাউন্টারকে n
পরিমাণে বৃদ্ধি করে। সাধারণত, আপনি goroutine শুরু করার আগে এটি কল করেন যাতে আপনি জানাতে পারেন যে কতগুলি goroutine শেষ হওয়ার জন্য অপেক্ষা করতে হবে।Done()
: কাউন্টার ১ কমিয়ে দেয়। প্রতিটি goroutine যখন তার কাজ শেষ করে তখন এটি কল করা উচিত।Wait()
: যতক্ষণ না কাউন্টার শূন্য হয়, অর্থাৎ সমস্ত goroutine শেষ হয়, ততক্ষণ এটি ব্লক থাকে।package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
// WaitGroup-এ 2 goroutine যোগ করা
wg.Add(2)
// প্রথম goroutine
go func() {
defer wg.Done() // কাজ শেষ হলে কাউন্টার কমানোর জন্য
time.Sleep(2 * time.Second)
fmt.Println("Goroutine 1 finished")
}()
// দ্বিতীয় goroutine
go func() {
defer wg.Done() // কাজ শেষ হলে কাউন্টার কমানোর জন্য
time.Sleep(1 * time.Second)
fmt.Println("Goroutine 2 finished")
}()
// সব goroutine শেষ হওয়া পর্যন্ত অপেক্ষা করা
wg.Wait()
fmt.Println("All goroutines finished")
}
🔹 Output:
Goroutine 2 finished
Goroutine 1 finished
All goroutines finished
👉 এখানে, wg.Wait()
নিশ্চিত করে যে প্রোগ্রামটি "All goroutines finished" মুদ্রণ করার আগে দুটি goroutine-এর কাজ শেষ হওয়া পর্যন্ত অপেক্ষা করে।
একটি Mutex ব্যবহৃত হয়, যাতে কেবলমাত্র এক goroutine এক সময়ে একটি নির্দিষ্ট কোড সেকশনে প্রবেশ করতে পারে, যা ডেটা রেস প্রতিরোধ করে। এটি শেয়ার করা রিসোর্সগুলির অ্যাক্সেস নিয়ন্ত্রণ করতে সাহায্য করে।
Lock()
: লক গ্রহণ করে। যদি অন্য কোনো goroutine ইতোমধ্যে লকটি ধারণ করে থাকে, তবে এই goroutine অপেক্ষা করবে যতক্ষণ না লকটি পাওয়া যায়।Unlock()
: লকটি মুক্ত করে। এটি অন্য goroutines-কে লকটি অর্জন করতে এবং তাদের কাজ চালিয়ে যেতে সাহায্য করে।package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
)
func increment() {
mu.Lock() // শেয়ার করা রিসোর্সে অ্যাক্সেস করতে লক নেয়া
counter++
mu.Unlock() // কাজ শেষ হলে লক মুক্ত করা
}
func main() {
var wg sync.WaitGroup
// 5 goroutine যোগ করা হচ্ছে WaitGroup-এ
wg.Add(5)
// 5 goroutine শুরু করা হচ্ছে, যেগুলি কাউন্টার বাড়াবে
for i := 0; i < 5; i++ {
go func() {
defer wg.Done() // কাজ শেষ হলে কাউন্টার কমানোর জন্য
increment()
}()
}
// সব goroutine শেষ হওয়া পর্যন্ত অপেক্ষা করা
wg.Wait()
fmt.Println("Counter value:", counter)
}
🔹 Output:
Counter value: 5
👉 এখানে, Mutex নিশ্চিত করে যে একসাথে একাধিক goroutine কাউন্টার পরিবর্তন করতে পারবে না, যা ডেটা রেস প্রতিরোধ করে এবং সঠিক ফলাফল নিশ্চিত করে।
আপনি WaitGroups এবং Mutex একসাথে ব্যবহার করতে পারেন গোরুটিনগুলো সিঙ্ক্রোনাইজ করতে এবং শেয়ার করা রিসোর্স নিরাপদভাবে অ্যাক্সেস করতে।
package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
)
func increment(wg *sync.WaitGroup) {
mu.Lock()
counter++
mu.Unlock()
wg.Done()
}
func main() {
var wg sync.WaitGroup
// WaitGroup-এ 5 goroutine যোগ করা হচ্ছে
wg.Add(5)
// 5 goroutine শুরু করা হচ্ছে, যেগুলি কাউন্টার বাড়াবে
for i := 0; i < 5; i++ {
go increment(&wg)
}
// সব goroutine শেষ হওয়া পর্যন্ত অপেক্ষা করা
wg.Wait()
fmt.Println("Final Counter value:", counter)
}
🔹 Output:
Final Counter value: 5
👉 এখানে, WaitGroup নিশ্চিত করে যে প্রধান ফাংশনটি সমস্ত goroutines শেষ হওয়া পর্যন্ত অপেক্ষা করবে, এবং Mutex নিশ্চিত করে যে একই সময়ে একাধিক goroutine কাউন্টার পরিবর্তন করবে না।