Pipeline adalah metode virtual untuk menghubungkan goroutine dan channel, sehingga output dari salah satu goroutine menjadi input untuk goroutine lainnya menggunakan channel untuk memindahkan data.

Keuntungan menggunakan pipeline adalah aliran data pada program kita selalu konstan, dimana kita tidak perlu menunggu setiap goroutine untuk menyelesaikan tugasnya.

Kerangka program

Program yang akan kita buat terdiri dari 4 fungsi, dimana dua fungsi akan kita gunakan sebagai goroutine (buatRandomData() dan cekDataDuplikat()), sedangkan tampilData() akan kita gunakan sebagai fungsi biasa dan akan dipanggil pada fungsi utama main().

Disini kita juga mendefinisikan dua variabel DATA untuk mengecek apakah ada data yang sama dengan data yang sudah dibuat dan variabel TutupChannelA untuk menutup channel. Variabel TutupChannelA digunakan untuk menutup channel utama ketika ada data yang sama.

package main

import (
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"time"
)

var TutupChannelA = false
var DATA = make(map[int]bool)

// menulis random data ke channel
func buatRandomData(min, max int, output chan<- int) {

}

// cek data duplikat, membaca dan menulis data ke channel
func cekDataDuplikat(input <-chan int, output chan<- int) {

}

// membaca data dari channel dan menjumlahkan nilainya
func tampilData(input <-chan int) {

}

//fungsi utama
func main() {

}

Cara kerja utama program

Program kita akan membutuhkan dua input integer (argumen1 dan argumen2) untuk selanjutnya membuat random data dari dua inputan yang di masukkan pengguna. inputan data pengguna akan diperoleh dari argumen yang diinputkan pengguna os.Args saat program di jalankan.

Selanjutnya untuk mengirimkan data antar goroutine kita menggunakan 2 channel (channelA dan channelB ). Dengan fungsi yang kita gunakan sebagai goroutine yaitu buatRandomData() dan cekDataDuplikat(), sedangkan fungsi tampilData() digunakan untuk menunggu data dari channel diterima semua.

//fungsi utama
func main() {
	//cek input pengguna
	if len(os.Args) != 3 {
		fmt.Println("Masukkan dua integer")
		os.Exit(1)
	}

	argumen1, _ := strconv.Atoi(os.Args[1])
	argumen2, _ := strconv.Atoi(os.Args[2])
	if argumen1 > argumen2 {
		fmt.Printf("Nilai %d harus lebih kecil dari %d",
			argumen1, argumen2)
		return
	}

	rand.Seed(time.Now().UnixNano())
	channelA := make(chan int)
	channelB := make(chan int)

	go buatRandomData(argumen1, argumen2, channelA)
	go cekDataDuplikat(channelA, channelB)
	tampilData(channelB)
}

Fungsi buat random data

Fungsi pertama yang akan kita gunakan sebagai goroutine memerlukan tiga argumen, argumen min dan max dari inputan pengguna program dan channel output dimana digunakan untuk menulis atau mengirim data.

Seperti yang bisa kita lihat channel output digunakan hanya untuk menulis data dimana simbol panahnya berada di sebelah kanan keyword chan (output chan<- int).

Didalam fungsi ini kita hanya membuat random angka di dalam perulangan yang tak terhingga, Jadi fungsi ini akan terus menulis random data selama kondisi channel tidak ditutup if TutupChannelA == true. Jika kondisinya terpenuhi maka channel output akan di tutup dan keluar dari perulangan.

// menulis random data ke channel
func buatRandomData(min, max int, output chan<- int) {
	for {
		if TutupChannelA == true {
			close(output)
			return
		}
		output <- rand.Intn(max-min) + min
	}
}

Fungsi untuk Mengecek data duplikat

Fungsi goroutine kedua kita dan goroutine terakhir yaitu cekDataDuplikat() menggunakan dua arah channel sebagai argumennya. channel pertama input <-chan int untuk dibaca atau diterima datanya dan channel kedua output chan<- int untuk menulis data atau mengirim data keluar dari fungsi.

Dari dua argumen tersebut kita bisa membedakan mana yang untuk mengirim dan menerima data, kita tidak bisa menggunakan channel input <-chan int untuk mengirim data dan sebaliknya juga pada channel output chan<- int.

Dalam fungsi ini kita mengecek apakah datanya sudah ada menggunakan data map dimana kita menggunakan nilai data dari channel untuk digunakan sebagai kunci DATA[value] data map tidak membolehkan ada kunci yang sama, jadi kita bisa memanfaatkan fitur ini.

Untuk perulangannya akan keluar sendiri ketika sudah tidak ada data yang diterima atau channel utama tidak lagi mengirimkan data (channel sudah ditutup). Jika channel utama ditutup maka channel output juga perlu ditutup, karena tidak ada data lagi yang perlu dikirim.

// cek data duplikat, membaca dan menulis data ke channel
func cekDataDuplikat(input <-chan int, output chan<- int) {
	for value := range input {
		_, sudahAda := DATA[value]
		if sudahAda == true {
			TutupChannelA = true
		} else {
			DATA[value] = true
			output <- value
		}
	}
	close(output)
}

Menampilkan data dan menjumlahkan nilai

Untuk fungsi menampilkan datanya akan dieksekusi langsung di fungsi utama program. Jadi kita akan menggunakan fungsi ini untuk menunggu sampai semua data dari channel diterima semua atau bisa diartikan bahwa semua fungsi goroutine selesai dengan tugasnya.

Fungsi tampil data hanya menerima data dari channel input <-chan int kemudian menampikan datanya ke console terminal. Penjumlahan nilainya hanya sebagai tambahan, kamu bisa menhapusnya, tapi disini kita akan menggunakannya untuk informasi tambahan di console.

// membaca data dari channel dan menjumlahkan nilainya
func tampilData(input <-chan int) {
	jumlah := 0
	for value := range input {
		fmt.Print(value, " ")
		jumlah = jumlah + value
	}
	fmt.Println("\nJumlah nilai data adalah", jumlah)
}

Menjalankan dan Hasil output program.

Untuk menjalankan program kita perlu menambahkan argumen seperti contoh go run main.go 2 9 dimana 2 dan 9 adalah argumen yang kita berikan pada program.

Dan disini kita bisa melihat bahwa program kita menjalankan semua goroutine dengan konstan menunggu semua goroutine selesai dan menampilkan output. Kita tidak tau urutan datanya karena datanya random tapi kita bisa melihat hasilnya semua di kumpulkan dengan sempurna.

> $ go run main.go 2 9
7 4 8 3 6 
Jumlah nilai data adalah 28