Goroutine, WaitGroup & Mutex

Budi Setiawan
2 min readFeb 10, 2024

--

Photo by Braden Collum on Unsplash

Ada permasalahan ketika kita tidak benar dalam mengguakan goroutines yaitu race codition dan deadlock. Race condition adalah ketika antar goroutine saling bersaing untuk melakukan sebuah eksekusi dan memodifikasi data yang sama sehingga data yang di modifikasi tidak valid dan hasilnya akan selalu tidak sama. Dibawah ini contoh race dan hasil dari counter akan berbeda beda setiap kali eksekusinya.

package main

import (
"fmt"
"time"
)

var counter = 0

func increment() {
temp := counter
time.Sleep(time.Millisecond) // Simulasi operasi yang memerlukan waktu
counter = temp + 1
}

func main() {
for i := 0; i < 5; i++ {
go increment()
}

time.Sleep(time.Second) // Menunggu goroutine selesai
fmt.Println("Nilai counter akhir:", counter)
}

Selain itu ada masalah lain yaitu deadlock yaitu ketika ada 2 atau lebih goroutine gagal berkomunikasi karena saling menunggu satu dengan lainnya.

WaitGroup

WaitGroup terdapat pada package sync dari Go digunakan untuk menunggu goroutine agar selesai melakukan eksekusi. Contoh penggunaannya.

package main

import (
"fmt"
"sync"
)

func main() {
var wg sync.WaitGroup

for i := 0; i < 5; i++ {
wg.Add(1)
go worker(i, &wg)
}

wg.Wait()
fmt.Println("Semua goroutine selesai.")
}

func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()

fmt.Printf("Goroutine %d sedang bekerja\n", id)
}

Mutex

Mutex (Mutual Exclusion) adalah mekanisme lain yang digunakan untuk mengamankan akses ke data bersamaan. Hanya satu goroutine yang dapat mengunci mutex pada suatu waktu, memastikan bahwa data tidak dimodifikasi oleh goroutine lain sampai mutex dilepaskan. Contoh penggunaan mutex.

Tanpa mutex

package main

import (
"fmt"
"sync"
)

var counter int

func main() {
var wg sync.WaitGroup

for i := 0; i < 10000; i++ {
wg.Add(1)
go increment(&wg)
}

wg.Wait()
fmt.Printf("Nilai counter akhir: %d\n", counter)
}

func increment(wg *sync.WaitGroup) {
defer wg.Done()

counter++
}

Hasil :

Dengan mutex

package main

import (
"fmt"
"sync"
)

var counter int
var mutex sync.Mutex

func main() {
var wg sync.WaitGroup

for i := 0; i < 10000; i++ {
wg.Add(1)
go increment(&wg)
}

wg.Wait()
fmt.Printf("Nilai counter akhir: %d\n", counter)
}

func increment(wg *sync.WaitGroup) {
defer wg.Done()

mutex.Lock()
counter++
mutex.Unlock()
}

Hasil:

Jika tanpa mutex maka code diatas akan menampilkan counter yang selalu berbeda beda setiap kali eksekusinya, ini terjadi karena ada race condition sehingga hasil akhirnya tidak selalu sama.

--

--

Budi Setiawan
Budi Setiawan

No responses yet