Apakah penggunaan contoh ini sync.WaitGroup
benar? Ini memberikan hasil yang diharapkan, tetapi saya tidak yakin tentang wg.Add(4)
dan posisi dari wg.Done()
. Apakah masuk akal untuk menambahkan empat goroutine sekaligus wg.Add()
?
http://play.golang.org/p/ecvYHiie0P
package main
import (
"fmt"
"sync"
"time"
)
func dosomething(millisecs time.Duration, wg *sync.WaitGroup) {
duration := millisecs * time.Millisecond
time.Sleep(duration)
fmt.Println("Function in background, duration:", duration)
wg.Done()
}
func main() {
var wg sync.WaitGroup
wg.Add(4)
go dosomething(200, &wg)
go dosomething(400, &wg)
go dosomething(150, &wg)
go dosomething(600, &wg)
wg.Wait()
fmt.Println("Done")
}
Hasil (seperti yang diharapkan):
Function in background, duration: 150ms
Function in background, duration: 200ms
Function in background, duration: 400ms
Function in background, duration: 600ms
Done
defer wg.Done()
panggilan awal di awal fungsi.Jawaban:
Ya, contoh ini benar. Penting agar
wg.Add()
terjadi sebelumgo
pernyataan untuk mencegah kondisi balapan. Hal berikut juga akan benar:Namun, tidak ada gunanya menelepon
wg.Add
berulang kali ketika Anda sudah tahu berapa kali akan dipanggil.Waitgroups
panik jika penghitung jatuh di bawah nol. Penghitung dimulai dari nol, masingDone()
- masing adalah a-1
dan masing-masingAdd()
bergantung pada parameter. Jadi, untuk memastikan bahwa meja tidak pernah turun di bawah dan panik menghindari, Anda perluAdd()
untuk dijamin untuk datang sebelumDone()
.Dalam Go, jaminan seperti itu diberikan oleh model memori .
Model memori menyatakan bahwa semua pernyataan dalam satu goroutine tampaknya dijalankan dalam urutan yang sama seperti saat ditulis. Mungkin saja mereka tidak benar-benar berada dalam urutan itu, tetapi hasilnya akan seperti semula. Juga dijamin bahwa goroutine tidak akan berjalan hingga
go
pernyataan yang memanggilnya . KarenaAdd()
terjadi sebelumgo
pernyataan dango
pernyataan muncul sebelumDone()
, kita tahuAdd()
terjadi sebelumDone()
.Jika Anda mendapatkan
go
pernyataan itu sebelumAdd()
, program dapat beroperasi dengan benar. Namun, itu akan menjadi kondisi balapan karena tidak ada jaminan.sumber
defer wg.Done()
jika kita yakin itu dipanggil terlepas dari rute yang diambil goroutine? Terima kasih.defer
dan salah satu goroutine Anda gagal memanggilwg.Done()
... bukankah Anda akanWait
memblokir selamanya? Sepertinya ini dapat dengan mudah memasukkan bug yang sulit ditemukan ke dalam kode Anda ...Saya akan merekomendasikan menyematkan
wg.Add()
panggilan ke dalamdoSomething()
fungsi itu sendiri, sehingga jika Anda menyesuaikan berapa kali dipanggil, Anda tidak perlu secara terpisah menyesuaikan parameter tambah secara manual yang dapat menyebabkan kesalahan jika Anda memperbaruinya tetapi lupa untuk memperbarui lainnya (dalam contoh sepele ini yang tidak mungkin, tetapi tetap saja, saya pribadi percaya ini adalah praktik yang lebih baik untuk penggunaan ulang kode).Seperti yang ditunjukkan oleh Stephen Weinberg dalam jawabannya untuk pertanyaan ini , Anda memang harus menaikkan grup tunggu sebelum memijahkan gofunc, tetapi Anda dapat melakukannya dengan mudah dengan membungkus bibit gofunc di dalam
doSomething()
fungsi itu sendiri, seperti ini:Kemudian Anda dapat memanggilnya tanpa
go
permintaan, misalnya:Sebagai taman bermain: http://play.golang.org/p/WZcprjpHa_
sumber
sumber