Kode ini memilih semua file xml dalam folder yang sama, sebagai executable yang dipanggil dan secara asinkron menerapkan pemrosesan ke setiap hasil dalam metode callback (dalam contoh di bawah, hanya nama file yang dicetak).
Bagaimana cara menghindari penggunaan metode tidur agar metode utama tidak keluar? Saya memiliki masalah dalam membungkus kepala saya di sekitar saluran (saya berasumsi itulah yang diperlukan, untuk menyinkronkan hasil) sehingga bantuan apa pun sangat dihargai!
package main
import (
"fmt"
"io/ioutil"
"path"
"path/filepath"
"os"
"runtime"
"time"
)
func eachFile(extension string, callback func(file string)) {
exeDir := filepath.Dir(os.Args[0])
files, _ := ioutil.ReadDir(exeDir)
for _, f := range files {
fileName := f.Name()
if extension == path.Ext(fileName) {
go callback(fileName)
}
}
}
func main() {
maxProcs := runtime.NumCPU()
runtime.GOMAXPROCS(maxProcs)
eachFile(".xml", func(fileName string) {
// Custom logic goes in here
fmt.Println(fileName)
})
// This is what i want to get rid of
time.Sleep(100 * time.Millisecond)
}
go
synchronization
goroutine
Dante
sumber
sumber
Note that calls with positive delta must happen before the call to Wait, or else Wait may wait for too small a group. Typically this means the calls to Add should execute before the statement creating the goroutine or other event to be waited for. See the WaitGroup example.
wg := new(sync.WaitGroup)
daripadavar wg sync.WaitGroup
.wg.Add(len(urls))
tepat di atas barisfor _, url := range urls
, saya percaya lebih baik karena Anda menggunakan Add hanya sekali.go vet
mendeteksi kasus ini dan memperingatkan dengan" func pass lock by value : sync.WaitGroup berisi sync.noCopy ".WaitGroups jelas merupakan cara kanonik untuk melakukan ini. Hanya demi kelengkapan, berikut solusi yang biasa digunakan sebelum WaitGroups diperkenalkan. Ide dasarnya adalah menggunakan saluran untuk mengatakan "Saya sudah selesai", dan minta goroutine utama menunggu hingga setiap rutinitas pemijahan melaporkan penyelesaiannya.
sumber
doSomething()
mengembalikan beberapa hasil, daripada Anda dapat meletakkannya di saluran, dan Anda dapat mengumpulkan dan memproses hasil di putaran kedua (segera setelah siap)wg.Add(1)
dan karenanya akan terus melacaknya. Dengan saluran, ini akan lebih sulit.c
berbeda dari goroutine utama yang membacac
. Jadi, goroutine utama selalu tersedia untuk membaca nilai dari saluran, yang akan terjadi jika salah satu goroutine tersedia untuk menulis nilai ke saluran. Anda benar bahwa jika kode ini tidak memunculkan goroutine tetapi menjalankan semuanya dalam satu goroutine, itu akan menemui jalan buntu.sync.WaitGroup dapat membantu Anda di sini.
sumber
Meskipun
sync.waitGroup
(wg) adalah cara kanonik maju, itu mengharuskan Anda melakukan setidaknya beberapawg.Add
panggilan Anda sebelum Andawg.Wait
untuk menyelesaikan semua. Ini mungkin tidak dapat dilakukan untuk hal-hal sederhana seperti web crawler, di mana Anda tidak mengetahui jumlah panggilan rekursif sebelumnya dan perlu beberapa saat untuk mengambil data yang mendorongwg.Add
panggilan tersebut. Lagi pula, Anda perlu memuat dan mengurai halaman pertama sebelum Anda mengetahui ukuran batch pertama halaman anak.Saya menulis solusi menggunakan saluran, menghindari
waitGroup
dalam solusi saya Tur Wisata Go - latihan perayap web . Setiap kali satu atau lebih go-rutin dimulai, Anda mengirimkan nomor tersebut kechildren
saluran. Setiap kali rutinitas pergi akan selesai, Anda mengirim1
kedone
saluran. Ketika jumlah anak sama dengan jumlah selesai, kita selesai.Satu-satunya kekhawatiran saya yang tersisa adalah ukuran
results
saluran yang di -hardcode , tetapi itu adalah batasan Go (saat ini).Kode sumber lengkap untuk solusinya
sumber
Berikut adalah solusi yang menggunakan WaitGroup.
Pertama, tentukan 2 metode utilitas:
Kemudian, ganti pemanggilan
callback
:Dengan panggilan ke fungsi utilitas Anda:
Langkah terakhir, tambahkan baris ini di akhir Anda
main
, bukan disleep
. Ini akan memastikan thread utama menunggu semua rutinitas selesai sebelum program dapat berhenti.sumber