pemrograman

Mengenal Package Context With Cancel Pada Golang

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.

comments powered by Disqus