Setelah memahami dasar concurrency dengan goroutines dan channels, langkah selanjutnya adalah mempelajari fitur lanjutan seperti select, context, dan pipeline pattern. Fitur ini akan membantu kita menulis program yang lebih robust, scalable, dan mudah dikelola.
select digunakan untuk menunggu banyak channel secara bersamaan. Mirip seperti switch, tapi khusus untuk operasi channel.
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(2 * time.Second)
ch1 <- "Data dari ch1"
}()
go func() {
time.Sleep(1 * time.Second)
ch2 <- "Data dari ch2"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println("Received:", msg1)
case msg2 := <-ch2:
fmt.Println("Received:", msg2)
}
}
}
Output:
Received: Data dari ch2
Received: Data dari ch1
select memungkinkan kita memilih channel mana yang lebih dulu siap.
context digunakan untuk mengatur lifecycle goroutine: cancel, timeout, dan deadline. Sangat berguna agar goroutine tidak jalan selamanya (goroutine leak).
package main
import (
"context"
"fmt"
"time"
)
func doWork(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("Pekerjaan dihentikan:", ctx.Err())
return
default:
fmt.Println("Bekerja...")
time.Sleep(500 * time.Millisecond)
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
go doWork(ctx)
time.Sleep(3 * time.Second)
fmt.Println("Selesai main program")
}
Output:
Bekerja...
Bekerja...
Bekerja...
Pekerjaan dihentikan: context deadline exceeded
Selesai main program
Pipeline adalah cara menyusun alur data antar goroutine. Setiap stage menerima data dari channel, memprosesnya, lalu mengirim ke channel berikutnya.
package main
import "fmt"
func generate(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
func main() {
nums := generate(1, 2, 3, 4, 5)
sq := square(nums)
for result := range sq {
fmt.Println(result)
}
}
Output:
1
4
9
16
25
Pipeline sangat berguna untuk memproses data bertahap, mirip assembly line.
Fitur lanjutan ini menjadikan concurrency di Golang lebih fleksibel, aman, dan mudah dikelola pada aplikasi berskala besar.