
Tidak semua bahasa pemrograman setara dalam hal penanganan concurrency. Go (Golang), Erlang, dan Elixir sering dipuji karena model concurrency-nya yang jauh lebih responsif, efisien, dan mudah ditulis dibandingkan bahasa lainnya.
Ada 4 faktor utama yang membuat model concurrency Go lebih baik dari lainnya:
Thread yang Sangat Ringan (Lightweight Threads)
Sebagian besar bahasa pemrograman tradisional (seperti Java lama atau C++) menggunakan OS-level Thread (dikelola langsung oleh Sistem Operasi). Persoalannya, OS Thread mengonsumsi memori sekitar 1–2 MB per thread. Menjalankan 10.000 thread sekaligus bisa langsung menghabiskan RAM belasan Gigabyte dan memicu crash.
Di lain pihak, Go dan Erlang menggunakan thread virtual yang dikelola oleh runtime bahasa itu sendiri, bukan OS. Satu Goroutine hanya membutuhkan memori sekitar 2 KB saat dibuat. Dengan ukuran thread sekecil itu, kamu bisa menjalankan ratusan ribu hingga jutaan Goroutine secara bersamaan bahkan pada laptop standar tanpa kehabisan memori.
Model Penjadwalan M:N (M:N Scheduler)
Bagaimana thread virtual tersebut dieksekusi di hardware fisik? Go menggunakan teknik M:N Scheduling, di mana Goroutines dipetakan secara dinamis ke
OS Threads (pada core CPU fisik). Teknik ini memberikan overhead yang rendah: berganti antar-thread OS (context switching) membutuhkan waktu lama karena CPU harus berpindah ke kernel mode. Namun, berganti antar-Goroutine dilakukan sepenuhnya di user mode sehingga puluhan kali lebih cepat.
Hal unik lainnya pada Go adalah Work Stealing alias mencuri kerjaan: Jika salah satu core CPU terlihat menganggur, scheduler secara otomatis akan “mencuri” tugas dari core lain yang sedang sibuk untuk diberikan kepadanya.
Filosofi Desain: Message Passing vs Shared Memory
Pada Java atau C++, concurrency tradisional memaksa Anda mengelola memori bersama menggunakan Lock atau Mutex (yang rentan memicu Race Condition dan Deadlock). Go dan Erlang mempopulerkan model CSP (Communicating Sequential Processes) atau Actor Model:
- Alih-alih membuat beberapa thread mengakses satu variabel yang sama, tugas-tugas terisolasi tersebut berkomunikasi dengan mengirimkan data melalui saluran khusus (disebut Channels di Go).
- Pendekatan ini secara alamiah mencegah race condition tanpa harus mengunci kode secara manual di banyak tempat.
Concurrency sejak awal adalah bagian integral dari desain Go
Di beberapa bahasa, concurrency menjadi fitur yang ditambahkan sebagai library atau add-on. Pada Go, concurrency adalah fitur yang terintegrasi langsung ke dalam Bahasa tersebut:
- Untuk membuat tugas concurrent, kamu cukup menambah satu kata kunci: go doSomething().
- Ada keyword native seperti select untuk menangani banyak channel sekaligus secara non-blocking.
- Alat pendeteksi bug seperti Race Detector sudah terpasang secara bawaan di compiler (go test -race atau go run -race).
Sekarang, bagaimana membandingkan Go dengan Node.js dalam hal penanganan concurrency?
Node.js lumayan tangguh untuk melayani beban request (I/O) dalam jumlah besar di waktu yang bersamaan. Namun apakah kemampuan concurrency-nya setara dengan Go?
Meskipun Goroutine (Go) dan Async/Await (JavaScript/Node.js) sama-sama digunakan untuk menangani tugas concurrent secara efisien tanpa memblokir aplikasi, keduanya memiliki fondasi arsitektur yang sangat berbeda. Perbedaan dasarnya terletak pada jumlah thread yang digunakan, cara eksekusi bergiliran (preemptive vs cooperative), dan gaya penulisan kodenya.
Node.js (Single-Thread) vs Go (Multi-Thread)
- JavaScript (Async/Await):
- Berjalan pada Single Thread (satu core CPU saja) berbasis Event Loop.
- Semua tugas berjalan pada satu alur utama. Saat ada tugas async (misal: panggil API), JS “mendelegasikan” tugas tersebut ke sistem operasi, lalu melanjutkan kode lain di thread utama.
- Async/Await pada JS sangat efisien untuk tugas I/O-bound biasa (akses database, HTTP request), tetapi tidak bisa memanfaatkan multi-core CPU secara otomatis untuk komputasi berat (CPU-bound). Ketika transaksi pada server kamu melibatkan komputasi berat (kriptografi, pengolahan data masif, enkripsi/dekripsi rumit), single thread pada Event Loop akan terblokir (blocking). Akibatnya, latency akan melonjak tinggi dan transaksi lain akan tertunda.
- Go (Goroutine):
- Berjalan di atas Multi-Thread (M:N Scheduler).
- Goroutine dieksekusi secara terdistribusi di seluruh core CPU yang tersedia di komputer.
- Dampak: Go secara otomatis memanfaatkan semua core CPU baik untuk tugas I/O-bound maupun komputasi berat (CPU-bound) tanpa perlu setup tambahan.
- Go dirancang khusus oleh Google untuk menangani arsitektur server berskala masif, multi-core, dan high-concurrency.
Jadi Pilih Yang Mana?
Pilih Node.js jika:
- Sistem yang kamu desain lebih banyak melakukan pekerjaan read/write data (I/O heavy) misalnya membaca/menulis ke database, meneruskan request HTTP, atau memanggil API lain. Untuk kerja semacam ini Node.js sudah sangat cukup.
- Kamu ingin lebih mudah merekrut orang, atau tim kamu skill-nya terkonsentrasi pada JavaScript/TypeScript. Programmer spesialis Node.js jauh lebih banyak dan mudah dicari daripada programmer Go (dan ini berpengaruh juga pada budget salary/hiring cost yang bakal dikeluarkan nantinya).
- Kamu ingin melakukan pengembangan dan deployment secepatnya (speed-to-market).
Pilih Go jika:
- Desain sistem dan jenis pekerjaan yang bakal dilakukan membutuhkan kerja komputasi berat, pemrosesan transaksi berkecepatan tinggi dengan latency serendah mungkin (misal: payment gateway, fintech, high-frequency trading).
- Kamu membutuhkan efisiensi penggunaan infrastruktur/server (menghemat biaya cloud pada skala besar).
- Kamu berniat membangun arsitektur microservices berskala besar sedari awal. Deadline dan jangka waktu development bukan isu utama buatmu.