Goroutine & Channel
Eksekusi bersamaan (concurrency) adalah salah satu kekuatan terbesar NusaScript yang diwarisi dari Go. Jalankan ribuan tugas secara paralel dengan mudah.
Apa itu Goroutine?
Goroutine adalah fungsi yang berjalan secara bersamaan (concurrent) dengan fungsi lain tanpa memblokir eksekusi program. Berbeda dengan thread OS yang berat, goroutine sangat ringan — Anda bisa menjalankan ribuan goroutine sekaligus.
| Konsep | Go | NusaScript |
|---|---|---|
| Goroutine | go fn() | luncurkan(fn) |
| Jeda program | time.Sleep(n) | tidur(ms) |
| Channel (buat) | make(chan T, n) | saluran_baru(n) |
| Kirim ke channel | ch <- val | kirim(ch, val) |
| Terima dari channel | <- ch | terima(ch) |
| Mutex baru | &sync.Mutex{} | kunci_baru() |
| Lock | mu.Lock() | kunci(mu) |
| Unlock | mu.Unlock() | buka_kunci(mu) |
| WaitGroup buat | &sync.WaitGroup{} | grup_tunggu() |
| WaitGroup Add | wg.Add(n) | tambah_tunggu(wg, n) |
| WaitGroup Done | wg.Done() | selesai_tunggu(wg) |
| WaitGroup Wait | wg.Wait() | tunggu_semua(wg) |
Goroutine Dasar — luncurkan()
Gunakan luncurkan(fn, arg1, arg2...) untuk menjalankan fungsi secara bersamaan.
fungsi ucapkan(nama) {
tampilkan("Halo dari goroutine:", nama)
}
// Jalankan 5 goroutine bersamaan
luncurkan(ucapkan, "Budi")
luncurkan(ucapkan, "Siti")
luncurkan(ucapkan, "Andi")
luncurkan(ucapkan, "Rini")
luncurkan(ucapkan, "Dani")
// Tunggu goroutine selesai (sederhana)
tidur(100)
tampilkan("Program selesai!")
Halo dari goroutine: Siti Halo dari goroutine: Budi Halo dari goroutine: Andi Halo dari goroutine: Dani Halo dari goroutine: Rini Program selesai!
Menunggu Goroutine — grup_tunggu()
Gunakan grup_tunggu() (WaitGroup) untuk menunggu semua goroutine selesai sebelum melanjutkan.
buat wg = grup_tunggu()
fungsi proses(id) {
tampilkan("Mulai proses", id)
tidur(200) // simulasi pekerjaan
tampilkan("Selesai proses", id)
selesai_tunggu(wg) // beri tahu WaitGroup bahwa goroutine ini selesai
}
// Tambah 3 goroutine ke counter
tambah_tunggu(wg, 3)
// Jalankan 3 goroutine bersamaan
luncurkan(proses, 1)
luncurkan(proses, 2)
luncurkan(proses, 3)
// Blokir sampai semua selesai
tunggu_semua(wg)
tampilkan("Semua proses selesai!")
Mulai proses 1 Mulai proses 2 Mulai proses 3 Selesai proses 2 Selesai proses 1 Selesai proses 3 Semua proses selesai!
Mutex — Proteksi Data Bersama
Saat beberapa goroutine mengakses variabel yang sama, gunakan kunci_baru() (Mutex) untuk mencegah race condition.
buat mu = kunci_baru()
buat counter = 0
buat wg = grup_tunggu()
fungsi tambah_counter() {
// Lock sebelum akses data bersama
kunci(mu)
counter += 1
buka_kunci(mu) // selalu unlock setelah selesai
selesai_tunggu(wg)
}
// Jalankan 1000 goroutine
tambah_tunggu(wg, 1000)
buat i = 0
selama i < 1000 {
luncurkan(tambah_counter)
i += 1
}
tunggu_semua(wg)
tampilkan("Counter akhir:", counter) // harus 1000
Counter akhir: 1000
Channel (Saluran) — Komunikasi Antar Goroutine
Channel adalah cara aman untuk berkomunikasi antar goroutine. Gunakan saluran_baru(n) untuk membuat channel dengan buffer ukuran n.
// Channel tanpa buffer (blocking)
buat ch = saluran_baru(0)
// Goroutine pengirim
fungsi kirim_data(saluran) {
buat i = 1
selama i <= 5 {
tampilkan("Mengirim:", i)
kirim(saluran, i)
i += 1
}
tutup_saluran(saluran)
}
luncurkan(kirim_data, ch)
// Penerima (di goroutine utama — blocking)
buat nilai = terima(ch)
selama nilai != nihil {
tampilkan("Menerima:", nilai)
nilai = terima(ch)
}
Mengirim: 1 Menerima: 1 Mengirim: 2 Menerima: 2 ...
Channel Berbufer
// Channel dengan buffer 5 — bisa kirim 5 tanpa menunggu penerima
buat ch = saluran_baru(5)
kirim(ch, "pesanan-1")
kirim(ch, "pesanan-2")
kirim(ch, "pesanan-3")
tampilkan("3 pesanan masuk antrian")
// Proses satu per satu
buat p1 = terima(ch)
buat p2 = terima(ch)
buat p3 = terima(ch)
tampilkan("Diproses:", p1, p2, p3)
Pola: Worker Pool
Worker Pool adalah pola concurrency dimana sekelompok goroutine (worker) memproses antrian pekerjaan (jobs) secara paralel.
buat jobs = saluran_baru(100) // antrian pekerjaan
buat results = saluran_baru(100) // hasil pekerjaan
buat wg = grup_tunggu()
// Worker — ambil job dari channel, proses, kirim hasil
fungsi worker(id, jobs_ch, results_ch) {
buat job = terima(jobs_ch)
selama job != nihil {
// Simulasi pekerjaan berat
buat hasil = job * job // kuadratkan angka
tampilkan("Worker", id, "proses job", job, "→", hasil)
kirim(results_ch, hasil)
job = terima(jobs_ch)
}
selesai_tunggu(wg)
}
// Buat 3 worker
tambah_tunggu(wg, 3)
luncurkan(worker, 1, jobs, results)
luncurkan(worker, 2, jobs, results)
luncurkan(worker, 3, jobs, results)
// Kirim 9 pekerjaan
buat i = 1
selama i <= 9 {
kirim(jobs, i)
i += 1
}
tutup_saluran(jobs)
// Tunggu semua worker selesai
tunggu_semua(wg)
tutup_saluran(results)
tampilkan("Semua pekerjaan selesai!")
Goroutine untuk Background Task
buat app = server_baru(8080)
// Background job: kirim reminder setiap 60 detik
fungsi kirim_reminder() {
selama benar {
tampilkan("[" + format_waktu(waktu_sekarang()) + "] Mengirim reminder email...")
// ... logika kirim email di sini
tidur(60000) // tunggu 60 detik
}
}
// Jalankan background job tanpa blokir server
luncurkan(kirim_reminder)
tambah_rute(app, "GET", "/", fungsi(req) {
kembalikan ke_json({"status": "ok", "waktu": format_waktu(waktu_sekarang())})
})
tampilkan("Server berjalan, background job aktif!")
jalankan_server(app)
kunci() dan buka_kunci() saat goroutine mengakses variabel yang dibagi bersama. Tanpa mutex, program bisa menghasilkan hasil yang tidak terduga akibat race condition.Fungsi Lanjut — tidur()
| Fungsi | Parameter | Keterangan |
|---|---|---|
tidur(ms) | milidetik | Jeda eksekusi N milidetik |
tidur(1000) | — | Jeda 1 detik |
tidur(500) | — | Jeda 0,5 detik |
tidur(60000) | — | Jeda 1 menit |