diff --git a/intermediate/concurrency/goroutines/README.md b/intermediate/concurrency/goroutines/README.md index ba6142e..2d0ac80 100644 --- a/intermediate/concurrency/goroutines/README.md +++ b/intermediate/concurrency/goroutines/README.md @@ -149,11 +149,69 @@ Selanjutnya, mari kita perhatikan goroutine `go alphabets()` dan `go numbers()`. ## Mendeklarasikan Channel Berikut cara mendeklarasikan, mengirim dan menerima data dari channel (kode diambil dari [https://golangbot.com/channels/](https://golangbot.com/channels/)) +### unbuffered channel ```Go a := make(chan int) // mendeklarasikan channel dengan tipe data integer +``` + +### buffered channel +channel juga dapat memiliki kapasitas (buffered), cukup dengan menspesifikasikan kapasitas/panjang data pada argument kedua fungsi make() +```go +// buffered channel dengan kapasitas 10 +b := make(chan int, 10) +``` + +buffered channel dapat digunakan untuk proses asinkron dimana data dapat disimpan dahulu hingga kapasitas penuh sebelum dikonsumsi goroutine lain. + +## Range dan close +Pengirim dapat menutup (close) channel untuk mengindikasikan bahwa tidak ada lagi value yang akan dikirim. Penerima dapat mengecek apakah channel sudah ditutup dengan meng-*assign* argumen kedua. [sumber](https://go.dev/tour/concurrency/4) +```go +v, ok := <-a +``` +ok adalah false jika tidak ada lagi value yang diterima dan channel ditutup + +channel juga dapat diiterasi menggunakan for loop: + +```go +for val := range a +``` +ia menerima value dari channel secara terus menerus hingga channel ditutup + +## data flow +Seperti terlihat pada contoh code sebelumnya, dapat dilihat bahwa data pada channel mengalir berdasarkan arah panah + +### contoh +```go +chan1 := make(chan int) +num := 1 +chan1 <- num // chan1 menerima (receive) data dari variabel num +var out int +out := <- chan1 // chan1 mengirim (send) data ke variabel out +``` -data := <- a // mengirim data dari channel a dan menyimpan hasilnya ke dalam variabel data -a <- data // channel a menerima data dari variabel data +### contoh data flow data channel pada parameter fungsi +```go +// contoh fungsi dengan parameter channel yang hanya menerima data channel +func terima(data <-chan int) { + receive := <-data + num := 1 + fmt.Printf("%d\n", receive) +} + +// contoh fungsi dengan parameter channel yang hanya mengirim data ke channel +func kirim(data chan<- int) { + num := 1 + data <- num + close(data) + // NOTE: channel sebaiknya ditutup dari sisi pengirim + // untuk menghindari goroutine penerima menunggu terus (deadlock) +} + +// contoh fungsi dengan parameter channel yang dapat mengirim maupun menerima data pada channel (bidirectional) +func duaArrah(dataChan chan int) { + num := <-dataChan + dataChan <- num +} ``` ## Contoh Penggunaan Channel diff --git a/intermediate/concurrency/goroutines/contoh_channel.go b/intermediate/concurrency/goroutines/contoh_channel.go new file mode 100644 index 0000000..3971bf0 --- /dev/null +++ b/intermediate/concurrency/goroutines/contoh_channel.go @@ -0,0 +1,61 @@ +package main + +import ( + "fmt" + "math/rand" + "sync" + "time" +) + +type Order struct { + Id int + status string +} + +func generateOrder(n int) []*Order { + orders := []*Order{} + + for i := range n { + order := Order{ + Id: i + 1, + status: "pending", + } + orders = append(orders, &order) + } + + return orders +} + +func processOrder(orderChan <-chan *Order, wg *sync.WaitGroup) { + defer wg.Done() + // loop berikut menerima value dari channel terus menerus hingga ditutup. + for order := range orderChan { + time.Sleep(time.Duration(rand.Intn(500)+10) * time.Millisecond) + status := []string{"delivered", "shipped"}[rand.Intn(2)] + order.status = status + fmt.Printf("procssing order: %d with status: %s\n", order.Id, order.status) + } +} + +func main() { + var wg sync.WaitGroup + wg.Add(2) + + n := 20 + orderChan := make(chan *Order, n) + + go func() { + wg.Done() + for _, order := range generateOrder(n) { + orderChan <- order + } + // karena kita mengirim data ke channel pada function ini, maka kita dapat panggil fungsi close di sini + close(orderChan) + fmt.Printf("done generating order\n") + }() + + go processOrder(orderChan, &wg) + + wg.Wait() + fmt.Printf("All operation is done!\n") +}