Pengenalan package context.WithCancel
Context
yang bisa menambahkan value, kita juga bisa menambahkan sinyal cancel ke dalam context. Biasanya context cancel
ini dipakai saat kita butuh menjalankan proses lain, dan kita ingin memberi cancel ke proses tersebut. context cancel ini dijalankan biasanya menggunakan goroutine yang berbeda sehingga dengan mudah kita ingin membatalkan proses eksekusi goroutine tersebut, jadi tingal kita kirim sinyal cancel ke dalam context maka goroutine yang ingin kita stop sudah bisa kita lakukan.
Kenapa kita harus menggunakan context?
Context.WithCancel
ini kita gunakan untuk membatasi proses ketika kita ingin menghentikan proses tersebut di suatu goroutine dan kita ingin melanjutkan proses ke proses selanjutnya atau proses yang lain. Jika kita ingin membuat context
dengan sinyal cancel, maka kita perlu menggunakan fungsi context.WithCancel(parent)
.
Implementasi dan sampel
Sebelum ke implementasi context.WithCancel
, kita akan simulasikan terlebih dahulu bagaimana ketika kode program kita terjadi memory leak
. Berikut dibawah ini kodenya.
Kita akan mengimplementasikannya dengan sampel kode dibawah ini.
func main() {
fmt.Println("Total Goroutine ", runtime.NumGoroutine())
destination := CreateCounter()
for n := range destination {
fmt.Println("Counter ", n)
if n == 10 {
break
}
}
fmt.Println("Total Goroutine ", runtime.NumGoroutine())
}
func CreateCounter() chan int {
destination := make(chan int)
go func() {
defer close(destination)
counter := 1
for {
destination <- counter
counter++
}
}()
return destination
}
Pada program diatas, kita akan membuat counter
dengan menggunakan satu goroutine ketika dipanggil di main
fungsi. Pada main
program kita akan menjalankan 10 counter saja agar tidak terlalu banyak saat dilakukan cetak ke terminal.
Maka alhasil ketika kita jalankan program tersebut akan mencetak seperti dibawah ini.
✗ go run app.go
Total Goroutine 1
Counter 1
Counter 2
Counter 3
Counter 4
Counter 5
Counter 6
Counter 7
Counter 8
Counter 9
Counter 10
Total Goroutine 2
Terlihat pada saat mencetak total goroutine yang dipakai adalah 1 saja karena main app yang kita jalankan itu sebenarnya akan berjalan dalam goroutine. Selanjutnya ketika selesai counter berjalan maka total goroutine akan bertambah menjadi 2 karena kita menjalankan program counter menggunakan 1 goroutine maka otomatis bertambah. Tetapi ketika kita terus memanggil goroutine dalam program ini maka nanti akan terus bertambah sehingga mengakibatkan konsumsi memori kita juga akan bertambah yang mana ini disebut dengan memory leak
.
Maka kita perlu mekanisme menghapus atau menghentikan proses goroutine
yang sudah tidak terpakai. Bagaimana caranya? Yaitu salah satunya bisa dengan menggunakan context.WithCancel
.
Lalu, bagaimana cara mengimplementasikan context.WithCancel
pada kode program sebelumnya? Baiklah kita lihat kode program yang sudah diperbaiki dengan menambahkan context.WithCancel
dibawah ini.
func main() {
parent := context.Background() // context parent
ctx, cancel := context.WithCancel(parent) // context child with cancel
fmt.Println("Total Goroutine ", runtime.NumGoroutine())
destination := CreateCounter(ctx)
for n := range destination {
fmt.Println("Counter ", n)
if n == 10 {
break
}
}
cancel()
time.Sleep(3 * time.Second)
fmt.Println("Total Goroutine ", runtime.NumGoroutine())
}
func CreateCounter(ctx context.Context) chan int {
destination := make(chan int)
go func() {
defer close(destination)
counter := 1
for {
select {
case <-ctx.Done():
return
default:
destination <- counter
counter++
}
}
}()
return destination
}
Penambahan pada kode diatas yaitu kita akan mengirimkan context
pada fungsi menggunakan parameter. Lalu context
tersebut kita pakai pada goroutine dan kita tambahkan seleksi select
yang mana ini digunakan untuk memastikan ketika proses pada fungsi main memanggil untuk cancel()
maka proses goroutine pun akan berhenti dan menghapus proses tersebut dalam memori.
Maka kita coba jalankan program setelah perbaikan dengan hasil dibawah ini.
✗ go run app.go
Total Goroutine 1
Counter 1
Counter 2
Counter 3
Counter 4
Counter 5
Counter 6
Counter 7
Counter 8
Counter 9
Counter 10
Total Goroutine 1
Terlihat pada akhir total goroutine akan terlihat hanya satu saja karena proses sebelumnya yang menjalankan goroutine karena kita panggil cancel()
maka proses tersebut akan berhenti otomatis goroutine-nya pun akan berhenti dan menghapus dari memori.
Kesimpulan
context.WithCancel
sangat perlu sekali digunakan jika kita menjalankan proses-proses secara paralel ataupun tidak bahkan ini menjadi suatu kewajiban bagi para developer golang agar tiap passing parameter dalam fungsi ditambahkan context
agar bisa melakukan cancel proses, dan menghindari dari goroutine yang terus berjalan tanpa digunakan karena prosesnya tidak diberhentikan.