Proses, Thread, dan Goroutine
Mulai dari analogi
Bayangkan sebuah restoran.
-
Restoran = program yang berjalan di komputer
-
Dapur = memory (RAM) yang dipakai program
-
Pelayan = yang handle request dari customer
Sekarang ada 100 customer datang bersamaan. Gimana restorannya handle ini?
Proses
Proses = satu program yang sedang berjalan, punya memory sendiri yang terpisah.
Analoginya: membuka restoran cabang baru untuk tiap customer. Tiap cabang punya dapur sendiri, pelayan sendiri, peralatan sendiri.
Proses A → punya RAM sendiri
Proses B → punya RAM sendiri (tidak bisa akses RAM proses A)
Proses C → punya RAM sendiriMasalahnya:
-
Buka cabang baru itu mahal dan lambat
-
Kalau ada 1000 customer, kamu perlu 1000 cabang — tidak realistis
Di dunia nyata: Browser Chrome membuka setiap tab sebagai proses terpisah. Makanya kalau satu tab crash, tab lain tidak ikut crash — tapi makanya juga Chrome makan banyak RAM.
Thread
Thread = unit kerja di dalam satu proses, berbagi memory yang sama.
Analoginya: satu restoran, tapi punya banyak pelayan. Semua pelayan pakai dapur yang sama, bahan yang sama.
Proses (1 restoran)
├── Thread 1 (pelayan 1) → handle customer A
├── Thread 2 (pelayan 2) → handle customer B
└── Thread 3 (pelayan 3) → handle customer CLebih efisien dari proses — tidak perlu buka cabang baru, cukup tambah pelayan.
Tapi ada masalah baru: Karena semua pelayan pakai dapur yang sama — kalau dua pelayan ambil bahan yang sama di waktu bersamaan, bisa tabrakan. Ini namanya race condition.
Contoh nyata:
Thread 1: baca stok produk → 10
Thread 2: baca stok produk → 10
Thread 1: kurangi stok → simpan 9
Thread 2: kurangi stok → simpan 9 ← harusnya 8, tapi jadi 9Data corrupt. Dan bug ini susah direproduksi karena tergantung timing.
Masalah lain: Setiap thread makan memory sekitar 1MB. Kalau ada 10.000 request bersamaan = 10GB RAM hanya untuk thread. Tidak scalable.
Goroutine
Goroutine = versi Go dari thread, tapi jauh lebih ringan.
Analoginya: pelayan yang bisa multitasking. Sambil nunggu pesanan customer A dimasak, dia langsung layani customer B. Tidak perlu nganggur.
Goroutine 1 → handle request A
↓ nunggu query database
(sambil nunggu, Go switch ke goroutine lain)
Goroutine 2 → handle request B
↓ nunggu response API
(sambil nunggu, Go switch lagi)
Goroutine 1 → database sudah selesai, lanjut prosesKenapa goroutine lebih efisien dari thread?
ThreadGoroutineMemory per unit1MB2KBDibuat olehOSGo runtimeBiaya buat baruMahalSangat murah10.000 unit10GB RAM20MB RAM
Goroutine 500x lebih hemat memory dari thread.
Cara pakai goroutine di Go
func handleRequest(userID int) {
// proses request
fmt.Println("handling user", userID)
}
func main() {
// tanpa goroutine — sequential, satu per satu
handleRequest(1)
handleRequest(2)
handleRequest(3)
// dengan goroutine — semua jalan bersamaan
go handleRequest(1)
go handleRequest(2)
go handleRequest(3)
}Tinggal tambah kata go di depan — fungsi itu langsung jalan di goroutine terpisah.
Tapi goroutine juga punya masalah yang sama dengan thread
Karena goroutine berbagi memory yang sama, race condition tetap bisa terjadi.
Go punya dua cara untuk handle ini:
1. Channel — goroutine komunikasi lewat "pipa"
ch := make(chan int)
go func() {
ch <- 42 // kirim data ke channel
}()
nilai := <-ch // terima data dari channel
fmt.Println(nilai) // 42Analoginya: pelayan tidak langsung ambil bahan dari dapur — mereka pesan lewat intercom, dan hanya satu yang bisa pesan di satu waktu.
2. Mutex — kunci pintu dapur
var mu sync.Mutex
stok := 10
go func() {
mu.Lock() // kunci dapur
stok -= 1 // ambil bahan
mu.Unlock() // buka kunci
}()Hanya satu goroutine yang bisa masuk "dapur" di satu waktu — yang lain nunggu di luar.
Hubungannya ke backend Go kamu
Setiap request yang masuk ke server Go otomatis dihandle di goroutine terpisah:
Request 1 masuk → Go buat goroutine 1
Request 2 masuk → Go buat goroutine 2
Request 3 masuk → Go buat goroutine 3Ini yang bikin Go sangat cocok untuk backend yang handle banyak request bersamaan — karena goroutine murah dan efisien.
Tapi ini juga kenapa kamu harus hati-hati:
-
Kalau dua goroutine akses variable yang sama tanpa proteksi → race condition → data corrupt
-
Kalau goroutine tidak pernah selesai → memory leak → server lambat lama-lama
Ringkasan
Proses → program terpisah, memory terpisah, berat
Thread → dalam satu proses, berbagi memory, lebih ringan tapi masih berat
Goroutine → seperti thread tapi 500x lebih ringan, dikelola Go runtime
Race condition → bug yang terjadi kalau dua goroutine akses data yang sama bersamaan
Channel → cara goroutine komunikasi dengan aman
Mutex → cara goroutine "antri" akses data yang sama