Kodeloka
  1. Kodeloka
  2. Kelas Golang
  3. Materi

Domain 6 · 11 bab

Goroutines & Concurrency

99. Concurrency vs Parallelism & Go Scheduler

Perbedaan Concurrency dan Parallelism, serta arsitektur M:N Scheduler Go.

Concurrency vs Parallelism

  • Concurrency: Menangani banyak hal sekaligus (1 kasir melayani antrean)
  • Parallelism: Eksekusi fisik bersamaan pada multi-core CPU (4 kasir bekerja)

Goroutine sangat ringan: hanya butuh ~2 KB memori awal vs Thread OS ~1-2 MB!

Contoh program

package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Println("CPU Cores:", runtime.NumCPU())
	fmt.Println("Goroutines Aktif:", runtime.NumGoroutine())
}

Praktik dan kuis bab ini di kelas interaktif →

100. Membuat Goroutines (keyword go)

Menjalankan fungsi secara asinkronus dengan keyword 'go'.

Keyword 'go'

Tambahkan go sebelum pemanggilan fungsi. Jika main() selesai duluan, goroutine anak langsung dihentikan paksa!

Contoh program

package main

import (
	"fmt"
	"time"
)

func DisplayNumber(n int) {
	fmt.Println("Goroutine:", n)
}

func main() {
	for i := 1; i <= 5; i++ {
		go DisplayNumber(i)
	}
	fmt.Println("Main selesai!")
	time.Sleep(100 * time.Millisecond)
}

Praktik dan kuis bab ini di kelas interaktif →

101. Channels (Kirim & Terima Data antar Goroutine)

Media komunikasi data antar Goroutine secara aman.

Channel

  • Buat: ch := make(chan string)
  • Kirim: ch <- "Data"
  • Terima: data := <-ch
  • Tutup: close(ch)

Unbuffered Channel bersifat blocking.

Contoh program

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan string)
	go func() {
		time.Sleep(100 * time.Millisecond)
		ch <- "Pesan dari Goroutine!"
	}()
	data := <-ch
	fmt.Println("Diterima:", data)
}

Praktik dan kuis bab ini di kelas interaktif →

102. Channel Direction & Buffered Channels

Membatasi arah channel (chan<- / <-chan) dan channel dengan kapasitas buffer.

Channel Direction & Buffer

  • chan<- string — In-Only (hanya kirim)
  • <-chan string — Out-Only (hanya terima)
  • make(chan string, 3) — Buffered (kapasitas 3)

Contoh program

package main

import "fmt"

func OnlyIn(ch chan<- string)  { ch <- "Hello" }
func OnlyOut(ch <-chan string) { fmt.Println(<-ch) }

func main() {
	ch := make(chan string)
	go OnlyIn(ch)
	OnlyOut(ch)
}

Praktik dan kuis bab ini di kelas interaktif →

103. Range & Close Channel, Select Multiplexing

Iterasi stream data dengan for range, menutup channel, dan select untuk multi-channel.

Range, Close, & Select

for data := range ch mengambil data sampai channel ditutup. select mendengarkan beberapa channel yang pertama siap.

Contoh program

package main

import "fmt"

func main() {
	ch := make(chan string, 3)
	go func() {
		for i := 1; i <= 3; i++ {
			ch <- fmt.Sprintf("Item-%d", i)
		}
		close(ch)
	}()
	for data := range ch {
		fmt.Println("Diterima:", data)
	}
}

Praktik dan kuis bab ini di kelas interaktif →

104. Race Condition & Data Race Problem

Bahaya konflik data saat banyak Goroutines memodifikasi variabel yang sama.

Race Condition

Terjadi ketika beberapa Goroutines mengubah data yang sama tanpa penguncian. Deteksi: go test -race atau go run -race main.go.

Contoh program

package main

import (
	"fmt"
	"time"
)

func main() {
	x := 0
	for i := 0; i < 1000; i++ {
		go func() {
			for j := 0; j < 100; j++ { x++ }
		}()
	}
	time.Sleep(500 * time.Millisecond)
	fmt.Println("x (harusnya 100000, tapi race condition):", x)
}

Praktik dan kuis bab ini di kelas interaktif →

105. sync.Mutex (Mutual Exclusion Lock)

Mengamankan data dari Race Condition dengan penguncian Mutex Lock/Unlock.

sync.Mutex

mutex.Lock() mengunci area kritikal. mutex.Unlock() melepas kunci. Hanya 1 Goroutine boleh masuk.

Contoh program

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	var mu sync.Mutex
	x := 0
	for i := 0; i < 1000; i++ {
		go func() {
			for j := 0; j < 100; j++ {
				mu.Lock()
				x++
				mu.Unlock()
			}
		}()
	}
	time.Sleep(500 * time.Millisecond)
	fmt.Println("x aman (tepat 100000):", x)
}

Praktik dan kuis bab ini di kelas interaktif →

106. sync.RWMutex (Reader-Writer Lock)

Optimasi performa kuncian dengan memisahkan Read Lock dan Write Lock.

sync.RWMutex

  • RLock()/RUnlock() — banyak reader sekaligus
  • Lock()/Unlock() — hanya 1 writer

Contoh program

package main

import (
	"fmt"
	"sync"
)

type SafeAccount struct {
	rw      sync.RWMutex
	balance int
}

func (a *SafeAccount) GetBalance() int {
	a.rw.RLock()
	defer a.rw.RUnlock()
	return a.balance
}

func main() {
	acc := SafeAccount{balance: 500000}
	fmt.Println("Saldo:", acc.GetBalance())
}

Praktik dan kuis bab ini di kelas interaktif →

107. sync.WaitGroup (Menunggu Goroutines Selesai)

Cara standar menunggu penyelesaian Goroutines tanpa time.Sleep.

sync.WaitGroup

  • wg.Add(n) — tambah counter
  • wg.Done() — kurangi counter
  • wg.Wait() — tunggu counter = 0

Contoh program

package main

import (
	"fmt"
	"sync"
	"time"
)

func Task(id int, wg *sync.WaitGroup) {
	defer wg.Done()
	fmt.Printf("Task %d bekerja...\n", id)
	time.Sleep(50 * time.Millisecond)
}

func main() {
	var wg sync.WaitGroup
	for i := 1; i <= 5; i++ {
		wg.Add(1)
		go Task(i, &wg)
	}
	wg.Wait()
	fmt.Println("SEMUA TASK SELESAI!")
}

Praktik dan kuis bab ini di kelas interaktif →

108. sync.Once, sync.Map, & sync/atomic

Eksekusi tunggal (Once), Map thread-safe (sync.Map), dan operasi atomic.

Utilitas Concurrency

  • sync.Once — fungsi hanya dieksekusi 1 kali
  • sync.Map — Map yang aman (Store/Load/Delete)
  • sync/atomic — operasi matematika tanpa lock

Contoh program

package main

import (
	"fmt"
	"sync/atomic"
)

func main() {
	var counter int64 = 0
	atomic.AddInt64(&counter, 1)
	atomic.AddInt64(&counter, 1)
	fmt.Println("Atomic Counter:", atomic.LoadInt64(&counter))
}

Praktik dan kuis bab ini di kelas interaktif →

109. Timer, Ticker, & GOMAXPROCS

Penjadwalan eksekusi satu kali (Timer), periodik (Ticker), dan pengaturan CPU cores.

Timer & Ticker

  • time.Timer — sinyal 1 kali
  • time.Ticker — sinyal periodik berulang
  • runtime.GOMAXPROCS(n) — atur jumlah OS Thread

Contoh program

package main

import (
	"fmt"
	"time"
)

func main() {
	ticker := time.NewTicker(100 * time.Millisecond)
	done := make(chan bool)
	go func() {
		time.Sleep(350 * time.Millisecond)
		done <- true
	}()
	for {
		select {
		case <-done:
			ticker.Stop()
			fmt.Println("Ticker Dihentikan!")
			return
		case t := <-ticker.C:
			fmt.Println("Tick:", t.Format("15:04:05.000"))
		}
	}
}

Praktik dan kuis bab ini di kelas interaktif →