sync.WaitGroup
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 64 dari 107.
Dalam pelajaran Dasar Goroutine, kita menggunakan time.Sleep untuk menunggu goroutine selesai, pendekatan yang rentan. sync.WaitGroup menyediakan cara yang tepat untuk menunggu sekumpulan goroutine menyelesaikan pekerjaannya.
WaitGroup bekerja seperti penghitung. Kamu menambah nilainya sebelum memulai goroutine, menguranginya saat goroutine selesai, dan menunggu hingga penghitung mencapai nol:
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1) // tambah penghitung
go func(id int) {
defer wg.Done() // kurangi penghitung setelah selesai
fmt.Printf("Worker %d finished\n", id)
}(i)
}
wg.Wait() // tunggu hingga penghitung bernilai 0
fmt.Println("All workers complete")
}Tiga method utama adalah Add(n) untuk menambah penghitung sebesar n, Done() untuk menguranginya sebanyak satu (setara dengan Add(-1)), dan Wait() untuk memblokir hingga penghitung mencapai nol. Menggunakan defer wg.Done() memastikan penghitung berkurang meskipun goroutine mengalami panic.
Kesalahan umum adalah memanggil Add di dalam goroutine, bukan sebelum goroutine dimulai. Hal ini menimbulkan kondisi balapan, sehingga Wait mungkin selesai sebelum semua goroutine terdaftar:
// Salah: kondisi balapan
go func() {
wg.Add(1) // mungkin berjalan setelah Wait()
defer wg.Done()
}()
// Benar: panggil Add sebelum meluncurkan fungsi
wg.Add(1)
go func() {
defer wg.Done()
}()WaitGroups sering disematkan dalam struct untuk mengoordinasikan operasi konkuren, sehingga penting untuk membangun tipe yang aman untuk thread di Go.
Tantangan
MudahMari kita buat pengelola unduhan yang mengoordinasikan beberapa unduhan file secara bersamaan menggunakan sync.WaitGroup. Pengelola ini akan melacak kapan semua unduhan selesai tanpa bergantung pada timer tidur sembarang.
Kamu akan menyusun kodemu dalam dua file:
downloader.go: Definisikan logika koordinasi unduhanmu.Buat struct
Downloaddengan fieldID(int),Filename(string), danSize(int, yang mewakili KB).Implementasikan method
Process(wg *sync.WaitGroup)padaDownloadyang menyimulasikan proses unduhan dengan tidur selama durasi berdasarkan ukuran file (gunakanSize * 10milidetik). Saat unduhan selesai, cetak:Downloaded: [Filename] ([Size]KB). Gunakandefer wg.Done()untuk memastikan penghitung WaitGroup berkurang dengan benar.Buat fungsi
StartDownloads(downloads []Download) intyang menjalankan semua unduhan secara bersamaan menggunakan goroutine dan menunggu sampai semuanya selesai. Ingat untuk memanggilwg.Add(1)sebelum menjalankan setiap goroutine, bukan di dalamnya. Kembalikan total ukuran semua unduhan.main.go: Baca informasi unduhan dan koordinasikan unduhan secara bersamaan.Baca jumlah unduhan, lalu untuk setiap unduhan baca ID, nama file, dan ukurannya. Buat unduhan dan teruskan ke
StartDownloads. Setelah semua unduhan selesai, cetak:All downloads complete: [total]KB total
Input berikut akan diberikan:
- Baris 1: Jumlah unduhan (integer)
- Baris-baris berikutnya: Untuk setiap unduhan, tiga baris berisi ID (integer), nama file (string), dan ukuran dalam KB (integer)
Contohnya, jika diberikan:
3
1
report.pdf
20
2
image.png
5
3
data.csv
10Outputmu akan menampilkan unduhan yang selesai (file yang lebih kecil selesai lebih dulu karena waktu tidurnya lebih singkat), lalu ringkasan:
Downloaded: image.png (5KB)
Downloaded: data.csv (10KB)
Downloaded: report.pdf (20KB)
All downloads complete: 35KB totalPerbedaan utama dibandingkan dengan menggunakan time.Sleep adalah wg.Wait() memblokir hingga semua goroutine memberi sinyal bahwa prosesnya selesai dengan Done(). Dengan begitu, kamu mendapatkan sinkronisasi yang akurat, terlepas dari berapa lama waktu yang dibutuhkan setiap unduhan.
Coba sendiri
package main
import (
"fmt"
)
func main() {
// Baca jumlah unduhan
var n int
fmt.Scanln(&n)
// Baca informasi unduhan
downloads := make([]Download, n)
for i := 0; i < n; i++ {
var id int
var filename string
var size int
fmt.Scanln(&id)
fmt.Scanln(&filename)
fmt.Scanln(&size)
downloads[i] = Download{
ID: id,
Filename: filename,
Size: size,
}
}
// TODO: Panggil StartDownloads dengan slice downloads
// TODO: Cetak ringkasannya: "All downloads complete: [total]KB total"
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1Dasar-Dasar OOP di Go
File EksternalWorkspace Go dan modulePaket dan ImporNama yang Diekspor dan Tidak DieksporPengantar OOP di Gostruct sebagai classMendefinisikan method pada structPointer receiver vs value receiverInisialisasi structFungsi KonstruktorUlasan: Kalkulator Sederhana4Interface
Pengenalan InterfaceImplementasi ImplisitInterface sebagai KontrakInterface Kosong (any)Type AssertionType SwitchKomposisi InterfaceInterface Stringer & ErrorUlasan: Kalkulator Bentuk7Enkapsulasi
Field yang Diekspor vs Tidak DieksporEnkapsulasi Tingkat PackageMethod Getter dan SetterPenyembunyian Informasi di GoRingkasan: Data Siswa10Generics (Go 1.18+)
Pengantar GenericsParameter TipeBatasan TipeStruct GenerikCara Alternatif untuk Method GenerikRingkasan Koleksi Generik2Mendalami Tipe dan Struct
Tipe Dasar dan KompositDefinisi Tipe KustomTag StructStruct AnonimStruct BersarangNilai Nol dan Nilai BawaanRangkuman: Buku Kontak5Komposisi daripada Pewarisan
Mengapa Go Tidak Memiliki PewarisanDasar Penyematan StructPromosi methodMenyematkan Beberapa StructPenyematan vs AgregasiMembayangi method yang DisematkanRangkuman: Hierarki Karyawan8Penanganan Error & OOP
Interface errorTipe Error KustomPembungkusan Error (fmt.Errorf)Error Sentinelerrors.Is() dan errors.As()Panic, Defer, dan RecoverRangkuman: Parser File3Pointer dan Memori
Dasar-Dasar Pointer di GoPointer ke StructPass by Value vs ReferenceFungsi new()Garbage Collection di GoRekap: Pembuat Linked List6Polimorfisme di Go
Polimorfisme melalui InterfaceDuck Typing di GoAturan Pemenuhan InterfaceKoleksi PolimorfikInjeksi DependensiRangkuman: Pemroses Pembayaran9Konkruensi & OOP
Dasar-dasar GoroutineChannel & KomunikasiChannel Ber-buffer vs Tanpa BufferPernyataan selectsync.Mutex & sync.RWMutexsync.WaitGroupDesain Struct yang Aman untuk ThreadRingkasan: Worker PoolLatihan sendiri: Compiler Go online